Bitdefender Hypervisor Memory Introspection
lixkernel.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "lixkernel.h"
6 #include "decoder.h"
7 #include "hook.h"
8 #include "lixvdso.h"
9 #include "alerts.h"
10 #include "lixksym.h"
11 
18 
22 static struct
23 {
26 } gPatchedSwapgs[128] = {0};
27 
32 
36 static QWORD gNativeSwapgs = 0;
37 
41 static BYTE gOriginalNativeSwapgs[0x10] = {0};
42 
46 
47 
52 __section(".detours") =
53 {
54  .FunctionName = "native_swapgs",
55  .MinVersion = DETOUR_MIN_VERSION_ANY,
56  .MaxVersion = DETOUR_MAX_VERSION_ANY,
57  .Callback = NULL,
58  .Tag = detTagSwapgs,
59  .EnableFlags = DETOUR_ENABLE_ALWAYS,
60 
61  .HandlersCount = 1,
62  .Handlers =
63  {
64  {
65  .MinVersion = DETOUR_MIN_VERSION_ANY,
66  .MaxVersion = DETOUR_MAX_VERSION_ANY,
67  .HypercallType = hypercallTypeNone,
68  .CodeLength = 5, // prologue + jmp back
69 
70  .Code = { 0 },
71 
72  .HypercallOffset = DETOUR_INVALID_HYPERCALL,
73  .RelocatedCodeOffset = 0x00,
74  },
75  },
76 };
77 
78 
79 static void
81  void
82  )
86 {
87  INTSTATUS status;
88  QWORD symEnd;
89  static BYTE lfence[3] = {0x0f, 0xae, 0xe8};
90 
92  {
93  return;
94  }
95 
97  {
98  return;
99  }
100 
101  gNativeSwapgs = IntKsymFindByName("native_swapgs", &symEnd);
102  if (!gNativeSwapgs)
103  {
104  ERROR("[ERROR] IntKsymFindByName could not find native_swapgs\n");
105  }
106  else if (symEnd - gNativeSwapgs != ARRAYSIZE(gOriginalNativeSwapgs))
107  {
108  WARNING("[WARNING] 'native_swapgs' size is 0x%llx, which we don't support!\n", symEnd - gNativeSwapgs);
109 
111  }
112  else
113  {
115  if (!INT_SUCCESS(status))
116  {
117  ERROR("[ERROR] IntKernVirtMemRead failed for %llx: %08x\n", gNativeSwapgs, status);
118  goto _instrument_kernel;
119  }
120 
121  if (gOriginalNativeSwapgs[0] == 0x0f &&
122  gOriginalNativeSwapgs[1] == 0x01 &&
123  gOriginalNativeSwapgs[2] == 0xf8 &&
124  gOriginalNativeSwapgs[3] == 0xc3)
125  {
126  BYTE newSwapgs[] =
127  {
128  0x0f, 0x01, 0xf8, // swapgs
129  0x0f, 0xae, 0xe8, // lfence
130  0xc3, // retn
131  };
132 
133  LOG("[SWAPGS] Overwriting native_swapgs...\n");
134 
135  status = IntKernVirtMemWrite(gNativeSwapgs, sizeof(newSwapgs), newSwapgs);
136  if (!INT_SUCCESS(status))
137  {
138  ERROR("[ERROR] IntKernVirtMemWrite failed for rip %llx: %08x\n", gNativeSwapgs, status);
139  goto _instrument_kernel;
140  }
141 
143  }
144  else if (gOriginalNativeSwapgs[0] == 0x55 &&
145  gOriginalNativeSwapgs[1] == 0x48 &&
146  gOriginalNativeSwapgs[2] == 0x89 &&
147  gOriginalNativeSwapgs[3] == 0xe5)
148  {
149  QWORD addr = 0;
150 
151  status = IntDetGetByTag(detTagSwapgs, &addr, NULL);
152  if (!INT_SUCCESS(status))
153  {
154  LOG("[SWAPGS] Detouring native_swapgs...\n");
155 
157  if (!INT_SUCCESS(status))
158  {
159  ERROR("[ERROR] IntDetSetHook failed for 'native_swapgs': %08x\n", status);
160  goto _instrument_kernel;
161  }
162 
163  status = IntDetGetByTag(detTagSwapgs, &addr, NULL);
164  if (!INT_SUCCESS(status))
165  {
166  ERROR("[ERROR] IntDetGetByTag failed after just setting it: %08x\n", status);
167  goto _instrument_kernel;
168  }
169 
170  //
171  // Instead of `MOV rbp, rsp`, do a `lfence`,
172  // since the function doesn't actually use any stack
173  //
174  status = IntKernVirtMemWrite(addr + 1, sizeof(lfence), lfence);
175  if (!INT_SUCCESS(status))
176  {
177  ERROR("[ERROR] Failed writing 'lfence' to the detour handler: %08x\n", status);
178  goto _instrument_kernel;
179  }
180 
182  }
183  else
184  {
185  LOG("[SWAPGS] 'native_swapgs' already detoured!");
186  }
187  }
188  else
189  {
190  WARNING("[WARNING] Unknown native_swapgs...\n");
191 
193  }
194  }
195 
196 _instrument_kernel:
197  for (QWORD page = gLixGuest->Layout.CodeStart;
198  page < gLixGuest->Layout.CodeEnd;
199  page += PAGE_SIZE)
200  {
201  BYTE *buf;
202 
203  status = IntVirtMemMap(page, PAGE_SIZE, gGuest.Mm.SystemCr3, 0, &buf);
204  if (!INT_SUCCESS(status))
205  {
206  ERROR("[ERROR]IntVirtMemMap failed for 0x%llx : %08x\n", page, status);
207  continue;
208  }
209 
210  for (QWORD rip = 0; rip < PAGE_SIZE;)
211  {
212  QWORD symStart;
213  char symName[LIX_SYMBOL_NAME_LEN];
214 
215  if (0x0F != buf[rip])
216  {
217  rip++;
218  continue;
219  }
220 
221  if (PAGE_REMAINING(rip) > 2 && (0x01 != buf[rip + 1] || 0xF8 != buf[rip + 2]))
222  {
223  rip++;
224  continue;
225  }
226  else if (PAGE_REMAINING(rip) <= 2)
227  {
228  BYTE rest[2] = { 0 };
229 
230  status = IntKernVirtMemRead(rip + 1, sizeof(rest), rest, NULL);
231  if (!INT_SUCCESS(status) || 0x01 != rest[0] || 0xF8 != rest[1])
232  {
233  rip++;
234  continue;
235  }
236  }
237 
238  status = IntKsymFindByAddress(page + rip, LIX_SYMBOL_NAME_LEN, symName, &symStart, &symEnd);
239  if (!INT_SUCCESS(status))
240  {
241  rip++;
242  continue;
243  }
244 
245  for (QWORD fRip = symStart; fRip < symEnd;)
246  {
247  INSTRUX instrux;
248 
249  status = IntDecDecodeInstruction(IG_CS_TYPE_64B, fRip, &instrux);
250  if (!INT_SUCCESS(status))
251  {
252  // The instruction is 'invalid' because the code-segment can be 16/32/64
253  TRACE("[SWAPGS] Function starts at %llx but it's instr at %llx is invalid (the code-segment type is not 64): %08x\n",
254  symStart, fRip, status);
255 
256  fRip++;
257  continue;
258  }
259 
260  if (instrux.Instruction != ND_INS_SWAPGS)
261  {
262  goto _next_instr;
263  }
264 
265  fRip += instrux.Length;
266  status = IntDecDecodeInstruction(IG_CS_TYPE_64B, fRip, &instrux);
267  if (!INT_SUCCESS(status))
268  {
269  fRip++;
270  continue;
271  }
272 
273  if (instrux.Length == 3 && instrux.Instruction == ND_INS_NOP)
274  {
275  LOG("[SWAPGS] RIP %llx in function %s\n", fRip - instrux.Length, symName);
276 
277  status = IntKernVirtMemRead(fRip,
279  gPatchedSwapgs[gTotalPatchedSwapgs].OriginalBytes,
280  NULL);
281  if (!INT_SUCCESS(status))
282  {
283  ERROR("[ERROR] IntKernVirtMemRead failed for rip %llx: %08x\n", fRip, status);
284  goto _next_instr;
285  }
286 
287  status = IntKernVirtMemWrite(fRip, sizeof(lfence), lfence);
288  if (!INT_SUCCESS(status))
289  {
290  ERROR("[ERROR] IntKernVirtMemWrite failed for rip %llx: %08x\n", fRip, status);
291  goto _next_instr;
292  }
293 
294  gPatchedSwapgs[gTotalPatchedSwapgs++].LfenceRip = fRip;
295  }
296  else
297  {
298  char nd[ND_MIN_BUF_SIZE];
299 
300  NdToText(&instrux, fRip, sizeof(nd), nd);
301  LOG("[SWAPGS] Ignoring at RIP %llx (%s) in function %s\n",
302  fRip - instrux.Length, nd, symName);
303  }
304 
306  {
307  ERROR("[ERROR] More than %d 'swapgs; nop[3]', bail out...\n", gTotalPatchedSwapgs);
308  break;
309  }
310 
311 _next_instr:
312  fRip += instrux.Length;
313  }
314 
315  rip = symEnd - page;
316  }
317 
318  IntVirtMemUnmap(&buf);
319  }
320 }
321 
322 
323 static void
325  void
326  )
330 {
331  INTSTATUS status;
332 
334  {
335  // Let's hope it's not interrupted in this function
336  for (DWORD cpu = 0; cpu < gGuest.CpuCount; cpu++)
337  {
338  IG_ARCH_REGS regs;
339 
340  status = IntGetGprs(cpu, &regs);
341  if (!INT_SUCCESS(status))
342  {
343  ERROR("[ERROR] IntGetGprs failed on cpu %d: %08x\n", cpu, status);
344  continue;
345  }
346 
347  if (regs.Rip >= gNativeSwapgs && regs.Rip < sizeof(gOriginalNativeSwapgs))
348  {
349  size_t offset = regs.Rip - gNativeSwapgs;
350 
351  switch (offset)
352  {
353  case 0:
354  LOG("[SWAPGS] RIP is at the start of patched native_swapgs, do nothing...\n");
355  break;
356 
357  case 6: // FALLTHROUGH
358  case 3:
359  LOG("[SWAPGS] RIP is %llx ('%s'), move it to %llx ('retn')...\n",
360  regs.Rip, offset == 3 ? "lfence" : "retn", gNativeSwapgs + 3);
361 
362  regs.Rip = gNativeSwapgs + 3;
363 
364  status = IntSetGprs(cpu, &regs);
365  if (!INT_SUCCESS(status))
366  {
367  ERROR("[ERROR] IntSetGprs failed: %08x\n", status);
368  }
369 
370  break;
371 
372  default:
373  LOG("[SWAPGS] Invalid RIP (%llx) position: %ld\n", regs.Rip, offset);
374  goto _restore_patched;
375  }
376  }
377  }
378 
379  LOG("[SWAPGS] Restore original 'native_swapgs' at RIP %llx\n", gNativeSwapgs);
380 
382  if (!INT_SUCCESS(status))
383  {
384  ERROR("[ERROR] IntKernVirtMemWrite failed for 'native_swapgs': %08x\n", status);
385  }
386 
388  }
389 
390 _restore_patched:
391  for (DWORD i = 0; i < gTotalPatchedSwapgs; i++)
392  {
394  {
395  ERROR("[ERROR] lfence rip %llx is not valid!\n", gPatchedSwapgs[i].LfenceRip);
396  continue;
397  }
398 
399  LOG("[SWAPGS] Restore at RIP %llx\n", gPatchedSwapgs[i].LfenceRip);
400 
401  status = IntKernVirtMemWrite(gPatchedSwapgs[i].LfenceRip,
402  sizeof(gPatchedSwapgs[i].OriginalBytes),
403  gPatchedSwapgs[i].OriginalBytes);
404  if (!INT_SUCCESS(status))
405  {
406  ERROR("[ERROR] IntKernVirtMemWrite failed for rip %llx: %08x\n",
407  gPatchedSwapgs[i].LfenceRip, status);
408  }
409 
410  memzero(&gPatchedSwapgs[i], sizeof(gPatchedSwapgs[i]));
411  }
412 
413  gTotalPatchedSwapgs = 0;
414 }
415 
416 
417 static INTSTATUS
419  _In_opt_ void *Context,
420  _In_ void *Hook,
421  _In_ QWORD Address,
422  _Out_ INTRO_ACTION *Action
423  )
436 {
437  INTSTATUS status;
438  EXCEPTION_VICTIM_ZONE victim = { 0 };
439  EXCEPTION_KM_ORIGINATOR originator = { 0 };
440  CHAR ksymRead[LIX_SYMBOL_NAME_LEN] = { 0 };
442  KERNEL_DRIVER *pDriver = Context;
443  HOOK_GVA *pGvaHook = NULL;
444  QWORD rip = gVcpu->Regs.Rip;
445  QWORD size = gVcpu->AccessSize;
446  QWORD gva = 0;
447  QWORD ksymStart = 0;
448  BOOLEAN exitAfterInformation = FALSE;
449 
450  *Action = introGuestNotAllowed;
451 
452  pGvaHook = (HOOK_GVA *)(((HOOK_GPA *)Hook)->Header.ParentHook);
453  gva = pGvaHook->GvaPage + (Address & PAGE_OFFSET);
454 
455  for (int p = 0; p < lixActivePatchCount; p++)
456  {
457  LIX_ACTIVE_PATCH *pActivePatch = &gLixGuest->ActivePatch[p];
458 
459  if (IN_RANGE_LEN(gva, pActivePatch->Gva, pActivePatch->Length))
460  {
461  *Action = introGuestAllowed;
462 
463  return INT_STATUS_SUCCESS;
464  }
465  }
466 
467  if ((gVcpu->Instruction.Instruction == ND_INS_VERW || gVcpu->Instruction.Instruction == ND_INS_VERR) &&
468  (PAGE_FRAME_NUMBER(gva) == PAGE_FRAME_NUMBER(rip)) && gVcpu->Instruction.Operands[0].Info.Memory.IsRipRel)
469  {
470  // VERW instruction is used to to cause the processor to overwrite buffer values that are affected by MDS
471  // The VERW operand is a valid writable data segment near the rip (e.g. RIP - 2)
472  // RIP:0xffffffff84d75ed6 'VERW word ptr [rel 0xffffffff84d75ed4]'
473 
474  *Action = introGuestAllowed;
475 
477  }
478 
479  status = IntKsymFindByAddress(gva, sizeof(ksymRead), ksymRead, &ksymStart, NULL);
480  if (!INT_SUCCESS(status))
481  {
482  ERROR("[ERROR] IntKsymFindByAddress failed for %llx: 0x%08x\n", gva, status);
483 
484  *Action = introGuestNotAllowed;
485  reason = introReasonInternalError;
486  }
487  else
488  {
489  if (gva + size - ksymStart <= 5)
490  {
491  *Action = introGuestAllowed;
492 
493  return INT_STATUS_SUCCESS;
494  }
495  }
496 
498 
499  status = IntExceptKernelGetOriginator(&originator, 0);
500  if (!INT_SUCCESS(status))
501  {
502  ERROR("[ERROR] IntExceptKernelGetOriginator failed with status: 0x%08x\n", status);
503 
504  *Action = introGuestNotAllowed;
505  reason = introReasonInternalError;
506 
507  exitAfterInformation = TRUE;
508  }
509 
510  status = IntExceptGetVictimEpt(pDriver,
511  Address,
512  gva,
514  ZONE_READ,
515  &victim);
516  if (!INT_SUCCESS(status))
517  {
518  ERROR("[ERROR] IntExceptGetVictimEpt failed with status: 0x%08x\n", status);
519 
520  *Action = introGuestNotAllowed;
521  reason = introReasonInternalError;
522 
523  exitAfterInformation = TRUE;
524  }
525 
526  if (exitAfterInformation)
527  {
528  IntExceptKernelLogInformation(&victim, &originator, *Action, reason);
529  }
530  else
531  {
532  IntExcept(&victim, &originator, exceptionTypeKm, Action, &reason, introEventEptViolation);
533  }
534 
536 
537  if (IntPolicyCoreTakeAction(pDriver->ProtectionFlag, Action, &reason))
538  {
539  EVENT_EPT_VIOLATION *pEptViol = &gAlert.Ept;
541 
542  memzero(pEptViol, sizeof(*pEptViol));
543 
544  pEptViol->Header.Action = *Action;
545  pEptViol->Header.Reason = reason;
546  pEptViol->Header.MitreID = idExploitRemote;
547 
548  pEptViol->Header.Flags = IntAlertCoreGetFlags(pDriver->ProtectionFlag, reason);
549 
551 
552  IntAlertFillLixKmModule(originator.Original.Driver, &pEptViol->Originator.Module);
554 
556 
558 
559  IntAlertEptFillFromVictimZone(&victim, pEptViol);
560 
561  status = IntKsymFindByAddress(gva, sizeof(ksym), ksym, NULL, NULL);
562  if (INT_SUCCESS(status))
563  {
564  memcpy(pEptViol->FunctionName, ksym, sizeof(pEptViol->FunctionName) - 1);
565  }
566 
567  IntLixDrvGetSecName(pDriver, gva, pEptViol->ModifiedSectionName);
568 
569  IntLixDrvGetSecName(originator.Original.Driver, originator.Original.Rip, pEptViol->RipSectionName);
570 
571  IntAlertFillVersionInfo(&pEptViol->Header);
572 
574 
576 
577  IntAlertEptFillFromVictimZone(&victim, pEptViol);
578 
579  status = IntNotifyIntroEvent(introEventEptViolation, pEptViol, sizeof(*pEptViol));
580  if (!INT_SUCCESS(status))
581  {
582  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
583  }
584  }
585 
587 
588  return INT_STATUS_SUCCESS;
589 }
590 
591 
592 static INTSTATUS
594  void
595  )
602 {
603  INTSTATUS status;
604  KERNEL_DRIVER *pDriver;
605 
606  pDriver = gGuest.KernelDriver;
607  if (NULL == pDriver)
608  {
610  }
611 
612  if (pDriver->Protected && (pDriver->ProtectionFlag & INTRO_OPT_PROT_KM_LX_TEXT_READS))
613  {
615  }
616 
617  if (NULL == pDriver->Lix.HookObjectRead)
618  {
620  if (!INT_SUCCESS(status))
621  {
622  ERROR("[ERROR] IntHookObjectCreate failed: 0x%08x\n", status);
623  return status;
624  }
625  }
626 
627  for (QWORD crtGva = gLixGuest->Layout.CodeStart; crtGva < gLixGuest->Layout.CodeEnd; crtGva += PAGE_SIZE)
628  {
629  if ((gLixGuest->Layout.CodeEnd - crtGva < PAGE_SIZE) &&
630  IN_RANGE(gLixGuest->Layout.ExTableStart, crtGva, crtGva + PAGE_SIZE))
631  {
632  continue;
633  }
634 
635  DWORD size = (DWORD)(gLixGuest->Layout.CodeEnd - crtGva < PAGE_SIZE ? gLixGuest->Layout.CodeEnd - crtGva : PAGE_SIZE);
636  status = IntHookObjectHookRegion(pDriver->Lix.HookObjectRead,
637  0,
638  crtGva,
639  size,
643  0,
644  NULL);
645  if (!INT_SUCCESS(status))
646  {
647  ERROR("[ERROR] IntHookObjectHookRegion failed for region 0x%016llx - 0x%016llx: 0x%08x\n",
648  crtGva, crtGva + PAGE_SIZE, status);
649  }
650  }
651 
653  pDriver->Protected = TRUE;
654 
655  return INT_STATUS_SUCCESS;
656 }
657 
658 
659 static INTSTATUS
661  void
662  )
669 {
670  INTSTATUS status;
671  KERNEL_DRIVER *pDriver;
672 
673  pDriver = gGuest.KernelDriver;
674  if (NULL == pDriver)
675  {
677  }
678 
679  if (pDriver->Protected && (pDriver->ProtectionFlag & INTRO_OPT_PROT_KM_LX))
680  {
682  }
683 
684  if (NULL == pDriver->HookObject)
685  {
687  if (!INT_SUCCESS(status))
688  {
689  ERROR("[ERROR] IntHookObjectCreate failed: 0x%08x\n", status);
690  return status;
691  }
692  }
693 
694  status = IntHookObjectHookRegion(pDriver->HookObject,
695  0,
701  0,
702  NULL);
703  if (!INT_SUCCESS(status))
704  {
705  ERROR("[ERROR] IntHookObjectHookRegion failed for region 0x%016llx - 0x%016llx: 0x%08x\n",
707  }
708 
709  status = IntHookObjectHookRegion(pDriver->HookObject,
710  0,
716  0,
717  NULL);
718  if (!INT_SUCCESS(status))
719  {
720  ERROR("[ERROR] IntHookObjectHookRegion failed for region 0x%016llx - 0x%016llx: 0x%08x\n",
722  }
723 
725  {
726  status = IntHookObjectHookRegion(pDriver->HookObject,
727  0,
733  0,
734  NULL);
735  if (!INT_SUCCESS(status))
736  {
737  ERROR("[ERROR] IntHookObjectHookRegion failed for region 0x%016llx - 0x%016llx : 0x%08x\n",
739  }
740  }
741  else
742  {
743  WARNING("[WARNING] ExTable is not available. Will skip protection.\n");
744  }
745 
746  pDriver->Protected = TRUE;
748 
749  return INT_STATUS_SUCCESS;
750 }
751 
752 
753 INTSTATUS
755  void
756  )
764 {
765  INTSTATUS status;
766 
767  status = IntLixHookKernelWrite();
768  if (!INT_SUCCESS(status))
769  {
770  ERROR("[ERROR] IntLixHookKernel failed: 0x%08x\n", status);
771  return status;
772  }
773 
775 
776  return INT_STATUS_SUCCESS;
777 }
778 
779 
780 INTSTATUS
782  void
783  )
791 {
792  INTSTATUS status;
793 
794  status = IntLixHookKernelRead();
795  if (!INT_SUCCESS(status))
796  {
797  ERROR("[ERROR] IntLixHookKernel failed: 0x%08x\n", status);
798  return status;
799  }
800 
802 
803  return INT_STATUS_SUCCESS;
804 }
805 
806 
807 static void
809  void
810  )
814 {
815  KERNEL_DRIVER *pDriver;
816 
817  pDriver = gGuest.KernelDriver;
818  if (NULL == pDriver)
819  {
820  return;
821  }
822 
824 
825  pDriver->Protected = FALSE;
826  pDriver->ProtectionFlag = 0;
827 
828  if (NULL == pDriver->HookObject)
829  {
830  return;
831  }
832 
834 }
835 
836 
837 static void
839  void
840  )
844 {
845  KERNEL_DRIVER *pDriver;
846 
847  pDriver = gGuest.KernelDriver;
848  if (NULL == pDriver)
849  {
850  return;
851  }
852 
853  pDriver->Protected = FALSE;
854  pDriver->ProtectionFlag = 0;
855 
856  if (NULL == pDriver->Lix.HookObjectRead)
857  {
858  return;
859  }
860 
862 }
863 
864 
865 void
867  void
868  )
872 {
874  {
876  }
877 
879 }
880 
881 
882 void
884  void
885  )
889 {
891  {
893  }
894 
896 }
Measures kernel mode exceptions checks.
Definition: stats.h:51
void * Module
The internal structure of a module.
Definition: exceptions.h:836
static void IntLixPatchSwapgs(void)
Finds vulnerable SWAPGS instruction inside the kernel and applies mitigations.
Definition: lixkernel.c:80
#define _In_opt_
Definition: intro_sal.h:16
#define DETOUR_ENABLE_ALWAYS
Can be used as the API_HOOK_DESCRIPTOR.EnableFlags to always enable the detour.
Definition: detours.h:429
struct _EVENT_EPT_VIOLATION::@284 Victim
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
_Bool BOOLEAN
Definition: intro_types.h:58
INTSTATUS IntLixKernelReadProtect(void)
Activates kernel protection.
Definition: lixkernel.c:781
Describes the information about a Linux active-patch.
Definition: lixguest.h:461
INTSTATUS IntVirtMemUnmap(void **HostPtr)
Unmaps a memory range previously mapped with IntVirtMemMap.
Definition: introcore.c:2234
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
Kernel module (ntoskrnl.exe, hal.dll, etc.).
Definition: intro_types.h:238
uint8_t BYTE
Definition: intro_types.h:47
Read-access hook.
Definition: glueiface.h:298
INTSTATUS IntKernVirtMemWrite(QWORD KernelGva, DWORD Length, void *Buffer)
Writes data to a guest kernel virtual memory range.
Definition: introcore.c:699
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
static BYTE gOriginalNativeSwapgs[0x10]
The original first 10 bytes of the "native_swapgs" function.
Definition: lixkernel.c:41
IG_ARCH_REGS Regs
The current state of the guest registers.
Definition: guests.h:95
LIX_ACTIVE_PATCH ActivePatch[lixActivePatchCount]
An array that contains information about the active-patches.
Definition: lixguest.h:527
#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 PAGE_REMAINING(addr)
Definition: pgtable.h:163
static void IntLixUnhookKernelRead(void)
Removes write hooks from the kernel code section.
Definition: lixkernel.c:838
#define STATS_EXIT(id)
Definition: stats.h:160
INTSTATUS IntGetGprs(DWORD CpuNumber, PIG_ARCH_REGS Regs)
Get the current guest GPR state.
Definition: introcpu.c:827
static DWORD gTotalPatchedSwapgs
The total number of patched swapgs gadgets.
Definition: lixkernel.c:31
#define INTRO_OPT_PROT_KM_LX
Enable kernel image protection (Linux only).
Definition: intro_types.h:409
QWORD RoDataStart
The guest virtual address where the read-only data starts.
Definition: lixguest.h:503
INTSTATUS IntKsymFindByAddress(QWORD Gva, DWORD Length, char *SymName, QWORD *SymStart, QWORD *SymEnd)
Finds the symbol which is located at the given address.
Definition: lixksym.c:1283
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
QWORD Flags
A combination of ALERT_FLAG_* values describing the alert.
Definition: intro_types.h:1198
#define PAGE_OFFSET
Definition: pgtable.h:32
#define ARRAYSIZE(A)
Definition: introdefs.h:101
#define INTRO_OPT_PROT_KM_LX_TEXT_READS
Enable kernel &#39;_text&#39; section read protection (Linux only).
Definition: intro_types.h:499
WORD Length
The patch length.
Definition: lixguest.h:464
#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
#define DETOUR_MAX_VERSION_ANY
Specifies that the first OS version for which a detour handler is available is the latest OS version ...
Definition: detours.h:317
int INTSTATUS
The status data type.
Definition: introstatus.h:24
QWORD GvaPage
Guest virtual page base address, aligned to 4K.
Definition: hook_gva.h:32
QWORD CodeEnd
The guest virtual address where the code ends.
Definition: lixguest.h:498
BOOLEAN Protected
True if the driver is protected, False if it is not.
Definition: drivers.h:65
QWORD CodeStart
The guest virtual address where the code starts.
Definition: lixguest.h:497
Describes a kernel-mode originator.
Definition: exceptions.h:943
static void IntLixUnhookKernelWrite(void)
Removes write hooks from the kernel code section.
Definition: lixkernel.c:808
static INTSTATUS IntLixHookKernelWrite(void)
Establishes read and write hooks for Kernel code.
Definition: lixkernel.c:660
void IntAlertFillCpuContext(BOOLEAN CopyInstruction, INTRO_CPUCTX *CpuContext)
Fills the current CPU context for an alert.
Definition: alerts.c:492
INSTRUX Instruction
The current instruction, pointed by the guest RIP.
Definition: guests.h:88
INTSTATUS IntLixKernelWriteProtect(void)
Activates kernel protection.
Definition: lixkernel.c:754
struct _EXCEPTION_KM_ORIGINATOR::@63 Return
EVENT_EPT_VIOLATION Ept
Definition: alerts.h:16
#define LOG(fmt,...)
Definition: glue.h:61
No hypercall. This detour does not generate events.
Definition: detours.h:187
Describes a kernel driver.
Definition: drivers.h:30
void IntAlertFillVersionInfo(INTRO_VIOLATION_HEADER *Header)
Fills version information for an alert.
Definition: alerts.c:327
DWORD AccessSize
The size of the memory access. Valid only for EPT exits.
Definition: guests.h:103
INTRO_VIOLATION_HEADER Header
The alert header.
Definition: intro_types.h:1217
void * HookObjectRead
The hook object used to protect this driver against read. NULL if the driver is not protected...
Definition: lixmodule.h:43
#define PAGE_FRAME_NUMBER(addr)
Definition: pgtable.h:181
INTRO_ACTION_REASON Reason
The reason for which Action was taken.
Definition: intro_types.h:1195
static INTSTATUS IntLixKernelHandleRead(void *Context, void *Hook, QWORD Address, INTRO_ACTION *Action)
Handles reads performed from a Kernel module&#39;s text section.
Definition: lixkernel.c:418
EXCEPTION_VICTIM_OBJECT Object
The modified object.
Definition: exceptions.h:895
QWORD ExTableStart
The guest virtual address where the ex-table starts.
Definition: lixguest.h:506
INTSTATUS IntAlertFillCodeBlocks(QWORD Rip, QWORD Cr3, BOOLEAN Execute, INTRO_CODEBLOCKS *CodeBlocks)
Fills the code blocks pattern for an alert.
Definition: alerts.c:71
EXCEPTION_VICTIM_MODULE Module
Used when a module is modified.
Definition: exceptions.h:869
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
#define DETOUR_MIN_VERSION_ANY
Specifies that the first OS version for which a detour handler is available is the first OS version s...
Definition: detours.h:314
INTSTATUS IntLixDrvHandleWrite(void *Context, void *Hook, QWORD Address, INTRO_ACTION *Action)
Called if an write occurs on the protected memory zone.
Definition: lixmodule.c:1236
void IntAlertEptFillFromVictimZone(const EXCEPTION_VICTIM_ZONE *Victim, EVENT_EPT_VIOLATION *EptViolation)
Fills the victim information inside an EPT alert.
Definition: alerts.c:868
#define IS_KERNEL_POINTER_LIX(p)
Definition: lixguest.h:11
#define INT_STATUS_NOT_INITIALIZED
Definition: introstatus.h:266
#define STATS_ENTER(id)
Definition: stats.h:153
struct _LINUX_GUEST::@126 Layout
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 IN_RANGE(x, start, end)
Definition: introdefs.h:167
#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 Current
The currently used options.
Definition: guests.h:236
#define __section(S)
Definition: common.h:76
#define IN_RANGE_LEN(x, start, len)
Definition: introdefs.h:175
#define TRUE
Definition: intro_types.h:30
INTSTATUS IntDetSetHook(QWORD FunctionAddress, QWORD ModuleBase, API_HOOK_DESCRIPTOR *Descriptor, API_HOOK_HANDLER *Handler)
Will inject code inside the guest.
Definition: detours.c:1061
#define TRACE(fmt,...)
Definition: glue.h:58
static BOOLEAN gNativeSwapgsHooked
Variable marking whether the "native_swapgs" function was detoured or not.
Definition: lixkernel.c:45
API_HOOK_DESCRIPTOR gSwapgsDetour
Hook descriptor for "native_swapgs" detour.
Definition: lixkernel.c:52
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
CHAR FunctionName[ALERT_MAX_FUNCTION_NAME_LEN]
The name of the modified function, if any. This is the same as Export.Name[0].
Definition: intro_types.h:1289
INTRO_EXEC_CONTEXT ExecContext
Information about the instruction that triggered the alert.
Definition: intro_types.h:1309
void IntLixDrvGetSecName(KERNEL_DRIVER *Driver, QWORD Gva, CHAR *SectionName)
Get the section of the driver that contains the provided guest virtual address.
Definition: lixmodule.c:913
LIX_KERNEL_MODULE Lix
Valid only for Linux guests.
Definition: drivers.h:71
#define WARNING(fmt,...)
Definition: glue.h:60
void * HookObject
The hook object used to protect this driver. NULL if the driver is not protected. ...
Definition: drivers.h:62
Sent when an EPT violation triggers an alert. See EVENT_EPT_VIOLATION.
Definition: intro_types.h:84
#define LIX_SYMBOL_NAME_LEN
The max length of the ksym as defined by Linux kernel.
Definition: lixguest.h:585
DWORD CpuCount
The number of logical CPUs.
Definition: guests.h:279
#define PAGE_SIZE
Definition: common.h:70
Describes the modified zone.
Definition: exceptions.h:893
uint32_t DWORD
Definition: intro_types.h:49
QWORD ProtectionFlag
The introcore option that decided that this driver must be protected.
Definition: drivers.h:49
enum _INTRO_ACTION INTRO_ACTION
Event actions.
QWORD Rip
The RIP from where the call to the exported function came.
Definition: exceptions.h:950
INTSTATUS IntSetGprs(DWORD CpuNumber, PIG_ARCH_REGS Regs)
Sets the values of the guest GPRs.
Definition: introcpu.c:905
QWORD RoDataEnd
The guest virtual address where the read-only data ends.
Definition: lixguest.h:504
__must_check INTSTATUS IntVirtMemMap(QWORD Gva, DWORD Length, QWORD Cr3, DWORD Flags, void **HostPtr)
Maps a guest virtual memory range inside Introcore virtual address space.
Definition: introcore.c:2134
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
static QWORD gNativeSwapgs
The guest virtual address of the "native_swapgs" function.
Definition: lixkernel.c:36
BYTE OriginalBytes[3]
The bytes that were modified with the lfence instruction.
Definition: lixkernel.c:25
#define DETOUR_INVALID_HYPERCALL
Used to specify that no hypercall is present in the detour handler so the HypercallOffset field insid...
Definition: detours.h:321
API_HOOK_HANDLER Handlers[DETOUR_MAX_HANDLERS]
Handlers that can be set for this function.
Definition: detours.h:388
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 IntKernVirtMemRead(QWORD KernelGva, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest kernel virtual memory range.
Definition: introcore.c:674
#define ZONE_READ
Used for read violation.
Definition: exceptions.h:735
CHAR ModifiedSectionName[ALERT_MAX_SECTION_NAME_LEN]
The name of the modified section, if any.
Definition: intro_types.h:1287
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
static struct @268 gPatchedSwapgs[128]
native_swapgs gadgets patched by Introspection.
KERNEL_DRIVER * KernelDriver
Points to the driver object that describes the kernel image.
Definition: guests.h:385
#define INTRO_OPT_PROT_KM_SWAPGS
Enable SWAPGS (CVE-2019-1125) mitigation.
Definition: intro_types.h:502
void IntLixKernelReadUnprotect(void)
Deactivates the kernel protection against read.
Definition: lixkernel.c:883
INTRO_PROCESS CurrentProcess
The current process.
Definition: intro_types.h:1197
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:59
INTRO_MODULE Module
The module that did the malicious access.
Definition: intro_types.h:1221
64-bit selector.
Definition: glueiface.h:188
CHAR RipSectionName[ALERT_MAX_SECTION_NAME_LEN]
The name of the section in which the RIP resides. May be empty.
Definition: intro_types.h:1279
Holds register state.
Definition: glueiface.h:30
Event structure for EPT violations.
Definition: intro_types.h:1215
void IntDisasmGva(QWORD Gva, DWORD Length)
This function disassembles a code buffer (given its GVA) and then dumps the instructions (textual dis...
Definition: dumper.c:432
void IntAlertFillLixCurrentProcess(INTRO_PROCESS *EventProcess)
Saves the current Linux process inside an event.
Definition: alerts.c:1310
QWORD Gva
The start of the region which follows to be patched.
Definition: lixguest.h:463
char CHAR
Definition: intro_types.h:56
void IntLixKernelWriteUnprotect(void)
Deactivates the kernel protection against write.
Definition: lixkernel.c:866
QWORD IntKsymFindByName(const char *Name, QWORD *SymEnd)
Searches the given Name in kallsyms and returns the Start & End offset.
Definition: lixksym.c:1399
static INTSTATUS IntLixHookKernelRead(void)
Establishes read hooks for Kernel code.
Definition: lixkernel.c:593
Exploitation of Remote Services.
Definition: intro_types.h:1159
#define INT_STATUS_REMOVE_HOOK_ON_RET
Can be used by hook callbacks in order to signal that the hook should be removed. ...
Definition: introstatus.h:343
static void IntLixUnpatchSwapgs(void)
Deactivates swapgs mitigations set by IntLixPatchSwapgs.
Definition: lixkernel.c:324
INTSTATUS IntDetGetByTag(DETOUR_TAG Tag, QWORD *Address, DWORD *Size)
Get a detour handler address and size by its tag.
Definition: detours.c:2110
Write-access hook.
Definition: glueiface.h:299
QWORD LfenceRip
The RIP where the lfence instruction was injected.
Definition: lixkernel.c:24
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
The number of entries.
Definition: lixguest.h:453
INTRO_PROT_OPTIONS CoreOptions
The activation and protection options for this guest.
Definition: guests.h:271
INTSTATUS IntDecDecodeInstruction(IG_CS_TYPE CsType, QWORD Gva, void *Instrux)
Decode an instruction from the provided guest linear address.
Definition: decoder.c:180
QWORD ExTableEnd
The guest virtual address where the ex-table ends.
Definition: lixguest.h:507
INTSTATUS IntHookObjectCreate(DWORD ObjectType, QWORD Cr3, void **Object)
Create a new hook object.
Definition: hook_object.c:81
Describes a function to be hooked.
Definition: detours.h:329
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
LINUX_GUEST * gLixGuest
Global variable holding the state of a Linux guest.
Definition: lixguest.c:30
INTRO_MODULE ReturnModule
The module to which the current code returns to.
Definition: intro_types.h:1222
#define FALSE
Definition: intro_types.h:34