Bitdefender Hypervisor Memory Introspection
lixvdso.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "lixvdso.h"
6 #include "alerts.h"
7 #include "decoder.h"
8 #include "hook.h"
9 #include "lixstack.h"
10 #include "lixksym.h"
11 
12 
13 #define LIX_VDSO_GPA_HOOK_PAGE_COUNT 3
14 
15 static void *gVdsoHook = NULL;
17 
18 
19 static LIX_SYMBOL gInitVdsoSym = { 0 };
20 static LIX_SYMBOL gAddNopsSym = { 0 };
22 
23 
24 
25 static void
27  _In_ QWORD Address,
29  _Out_ INTRO_ACTION *Action,
31  )
42 {
44  EXCEPTION_KM_ORIGINATOR originator = { 0 };
45  EXCEPTION_VICTIM_ZONE victim = { 0 };
46  BOOLEAN except = TRUE;
47 
48  *Reason = introReasonUnknown;
49  *Action = introGuestNotAllowed;
50 
52 
53  status = IntExceptKernelGetOriginator(&originator, 0);
54  if (status == INT_STATUS_EXCEPTION_BLOCK)
55  {
56  *Reason = introReasonNoException;
57  except = FALSE;
58  }
59  else if (!INT_SUCCESS(status))
60  {
61  ERROR("[ERROR] IntExceptKernelGetOriginator failed with status: 0x%08x\n", status);
62  *Reason = introReasonInternalError;
63  except = FALSE;
64  }
65 
66  status = IntExceptGetVictimEpt(NULL, Address, gVcpu->Gla, Type, ZONE_WRITE, &victim);
67  if (!INT_SUCCESS(status))
68  {
69  *Reason = introReasonInternalError;
70  ERROR("[ERROR] IntExceptGetVictimEpt failed with status: 0x%08x\n", status);
71  except = FALSE;
72  }
73 
74  if (except)
75  {
76  IntExcept(&victim, &originator, exceptionTypeKm, Action, Reason, introEventEptViolation);
77  }
78  else
79  {
80  IntExceptKernelLogInformation(&victim, &originator, *Action, *Reason);
81  }
82 
84 }
85 
86 
87 static void
89  _In_ QWORD Address,
91  _Out_ INTRO_ACTION *Action,
93  )
104 {
105  INTSTATUS status = INT_STATUS_SUCCESS;
106  LIX_TASK_OBJECT *pTask = NULL;
107  INSTRUX *pInstrux = &gVcpu->Instruction;
108  EXCEPTION_UM_ORIGINATOR originator = { 0 };
109  EXCEPTION_VICTIM_ZONE victim = { 0 };
110  BOOLEAN except = TRUE;
111 
112  *Reason = introReasonUnknown;
113  *Action = introGuestNotAllowed;
114 
115  pTask = IntLixTaskGetCurrent(gVcpu->Index);
116  if (NULL == pTask)
117  {
118  ERROR("[ERROR] No current task on CPU %d\n", gVcpu->Index);
119  except = FALSE;
120  }
121 
123 
124  if (pTask != NULL)
125  {
126  status = IntExceptUserGetOriginator(pTask, TRUE, gVcpu->Regs.Rip, pInstrux, &originator);
127  if (status == INT_STATUS_EXCEPTION_BLOCK)
128  {
129  *Reason = introReasonNoException;
130  except = FALSE;
131  }
132  else if (!INT_SUCCESS(status))
133  {
134  ERROR("[ERROR] IntExceptUserGetOriginator failed with status: 0x%08x\n", status);
135  *Reason = introReasonInternalError;
136  except = FALSE;
137  }
138  }
139 
140  status = IntExceptGetVictimEpt(NULL, Address, gVcpu->Gla, Type, ZONE_WRITE, &victim);
141  if (!INT_SUCCESS(status))
142  {
143  *Reason = introReasonInternalError;
144  ERROR("[ERROR] IntExceptGetVictimEpt failed with status: 0x%08x\n", status);
145  except = FALSE;
146  }
147 
149 
150  if (except)
151  {
152  IntExcept(&victim, &originator, exceptionTypeUm, Action, Reason, introEventEptViolation);
153  }
154  else
155  {
156  IntExceptUserLogInformation(&victim, &originator, *Action, *Reason);
157  }
158 
160 }
161 
162 
163 static INTSTATUS
165  _In_opt_ void *Context,
166  _In_ HOOK_GPA *Hook,
167  _In_ QWORD Address,
168  _Out_ INTRO_ACTION *Action
169  )
184 {
185  INTSTATUS status;
186  INTRO_OBJECT_TYPE type = (INTRO_OBJECT_TYPE)(QWORD)(Context);
188 
189  *Action = introGuestNotAllowed;
190 
192  {
193  IntLixVdsoHandleKernelModeWrite(Address, type, Action, &reason);
194  }
195  else
196  {
197  IntLixVdsoHandleUserModeWrite(Address, type, Action, &reason);
198  }
199 
200  if (IntPolicyCoreTakeAction(INTRO_OPT_PROT_KM_VDSO, Action, &reason))
201  {
202  EVENT_EPT_VIOLATION *pEptViol = &gAlert.Ept;
203  memzero(pEptViol, sizeof(*pEptViol));
204 
205  pEptViol->Header.Action = *Action;
207  pEptViol->Header.MitreID = idHooking;
208 
210 
211  pEptViol->Header.Flags &= ~ALERT_FLAG_NOT_RING0;
212 
214 
216  {
218  if (pDriver)
219  {
220  IntAlertFillLixKmModule(pDriver, &pEptViol->Originator.Module);
221  }
222  }
223 
224  pEptViol->Victim.Type = type;
225 
227 
228  pEptViol->Offset = gVcpu->Gla & PAGE_OFFSET;
229  pEptViol->VirtualPage = gVcpu->Gla & PAGE_MASK;
230  pEptViol->PhysicalPage = Hook->GpaPage;
231 
232  pEptViol->HookStartVirtual = gVcpu->Gla & PAGE_MASK;
233  pEptViol->HookStartPhysical = Hook->GpaPage;
234 
235  pEptViol->Violation = IG_EPT_HOOK_WRITE;
236  pEptViol->ZoneTypes = ZONE_LIB_CODE;
237 
238  IntAlertFillVersionInfo(&pEptViol->Header);
239 
241  IntAlertFillExecContext(0, &pEptViol->ExecContext);
242 
243  status = IntNotifyIntroEvent(introEventEptViolation, pEptViol, sizeof(*pEptViol));
244  if (!INT_SUCCESS(status))
245  {
246  WARNING("[WARNING] IntNotifyIntroEvent failed: 0x%08x\n", status);
247  }
248  }
249 
251 
252  return INT_STATUS_SUCCESS;
253 }
254 
255 
256 static __forceinline BOOLEAN
258  _In_ QWORD Rip
259  )
271 {
272  return (IN_RANGE(Rip, gTextPokeEarlySym.Start, gTextPokeEarlySym.End) ||
273  IN_RANGE(Rip, gAddNopsSym.Start, gAddNopsSym.End) ||
274  IN_RANGE(Rip, gInitVdsoSym.Start, gInitVdsoSym.End));
275 }
276 
277 
278 static INTSTATUS
280  _In_opt_ void *Context,
281  _In_ void *Hook,
282  _In_ QWORD Address,
283  _Out_ INTRO_ACTION *Action
284  )
299 {
300  INTSTATUS status = INT_STATUS_SUCCESS;
301  IG_ARCH_REGS *pRegs = &gVcpu->Regs;
302  STACK_TRACE st = { 0 };
303  STACK_ELEMENT stElements[8] = { 0 };
304 
305  st.Traces = stElements;
306 
307  if (IntLixVdsoIsInitWrite(pRegs->Rip))
308  {
309  *Action = introGuestAllowed;
310  return INT_STATUS_SUCCESS;
311  }
312 
313  status = IntLixStackTraceGetReg(0, pRegs, ARRAYSIZE(stElements), 0, &st);
314  if (INT_SUCCESS(status) && st.NumberOfTraces > 0)
315  {
316  for (DWORD i = 0; i < st.NumberOfTraces; i++)
317  {
319  {
320  *Action = introGuestAllowed;
321  return INT_STATUS_SUCCESS;
322  }
323  }
324  }
325 
326  return IntLixVdsoHandleWriteCommon(Context, Hook, Address, Action);
327 }
328 
329 
330 static INTSTATUS
332  _In_ char *FunctionName,
333  _Out_ QWORD *Address
334  )
348 {
349  INTSTATUS status;
350  INSTRUX instrux;
351  QWORD funcStart = 0;
352  QWORD funcEnd = 0;
353  QWORD mapVdsoAddr;
354  QWORD address = 0;
355  QWORD rdiValue = 0;
356 
357  mapVdsoAddr = IntKsymFindByName("map_vdso", NULL);
358  if (!mapVdsoAddr)
359  {
360  ERROR("[ERROR] IntKsymFindByName could not find map_vdso\n");
361  return INT_STATUS_NOT_FOUND;
362  }
363 
364  funcStart = IntKsymFindByName(FunctionName, &funcEnd);
365  if (!funcStart)
366  {
367  ERROR("[ERROR] Could not find %s in kallsyms\n", FunctionName);
368  return INT_STATUS_NOT_FOUND;
369  }
370 
371  rdiValue = 0;
372  while (funcStart < funcEnd)
373  {
374  status = IntDecDecodeInstruction(IG_CS_TYPE_64B, funcStart, &instrux);
375  if (!INT_SUCCESS(status))
376  {
377  ERROR("[ERROR] IntDecDecodeInstruction failed: %08x\n", status);
378  return status;
379  }
380 
381  funcStart += instrux.Length;
382 
383  if (ND_INS_MOV == instrux.Instruction &&
384  instrux.Operands[0].Type == ND_OP_REG &&
385  instrux.Operands[0].Info.Register.Reg == NDR_RDI) // mov RDI, vdso_image_64;
386  {
387  if (instrux.Operands[1].Type == ND_OP_IMM)
388  {
389  rdiValue = SIGN_EX_32(instrux.Operands[1].Info.Immediate.Imm);
390  }
391  else if (instrux.Operands[1].Type == ND_OP_MEM)
392  {
393  QWORD tmp = funcStart + instrux.Operands[1].Info.Memory.Disp;
394  status = IntKernVirtMemFetchQword(tmp, &tmp);
395  if (!INT_SUCCESS(status))
396  {
397  ERROR("[ERROR] IntKernVirtMemFetchQword failed for 0x016%llx: 0x%08x\n", tmp, status);
398  }
399  else
400  {
401  rdiValue = tmp;
402  }
403  }
404  else
405  {
406  ERROR("[ERROR] Unsupported operand type for <mov rdi, ...> instruction: %d\n",
407  instrux.Operands[1].Type);
408  }
409 
410  continue;
411  }
412 
413  if ((instrux.Instruction == ND_INS_CALLNR || instrux.Instruction == ND_INS_JMPNR) &&
414  instrux.Operands[0].Type == ND_OP_OFFS &&
415  mapVdsoAddr == (funcStart + instrux.Operands[0].Info.RelativeOffset.Rel))
416  {
417  address = rdiValue;
418  break;
419  }
420  }
421 
422  if (address)
423  {
424  *Address = address;
425  return INT_STATUS_SUCCESS;
426  }
427 
428  return INT_STATUS_NOT_FOUND;
429 }
430 
431 
432 static INTSTATUS
434  void
435  )
449 {
450  INTSTATUS status = INT_STATUS_SUCCESS;
451 
452  if (LIX_FIELD(Info, HasVdsoImageStruct))
453  {
454  QWORD vdsoImage = 0;
455  QWORD vdsoSize = 0;
456 
457  vdsoImage = IntKsymFindByName("vdso_image_64", NULL);
458  if (!vdsoImage)
459  {
460  status = IntLixVdsoResolveImageAddress("arch_setup_additional_pages", &vdsoImage);
461  if (!INT_SUCCESS(status))
462  {
463  ERROR("[ERROR] vdso_image_64 not found: 0x%08x\n", status);
464  return status;
465  }
466  }
467 
468  status = IntKernVirtMemFetchQword(vdsoImage, &gLixGuest->Vdso.VdsoStart);
469  if (!INT_SUCCESS(status))
470  {
471  ERROR("[ERROR] Failed fetching from vdso_image %llx: 0x%08x\n", vdsoImage, status);
472  return status;
473  }
474 
475  status = IntKernVirtMemFetchQword(vdsoImage + sizeof(QWORD), &vdsoSize);
476  if (!INT_SUCCESS(status))
477  {
478  ERROR("[ERROR] Failed fetching from vdso_image %llx: 0x%08x\n", vdsoImage, status);
479  return status;
480  }
481 
482  if (vdsoSize > 2 * PAGE_SIZE)
483  {
484  WARNING("[WARNING] vdso size is too large: %llu!\n", vdsoSize);
485  vdsoSize = 2 * PAGE_SIZE;
486  }
487 
488  gLixGuest->Vdso.VdsoEnd = gLixGuest->Vdso.VdsoStart + vdsoSize;
489 
490  vdsoImage = IntKsymFindByName("vdso_image_x32", NULL);
491  if (!vdsoImage)
492  {
493  status = IntLixVdsoResolveImageAddress("compat_arch_setup_additional_pages", &vdsoImage);
494  if (!INT_SUCCESS(status))
495  {
496  WARNING("[WARNING] vdso_image_x32 not found: 0x%08x\n", status);
497  goto _exit;
498  }
499  }
500 
501  status = IntKernVirtMemFetchQword(vdsoImage, &gLixGuest->Vdso.Vdso32Start);
502  if (!INT_SUCCESS(status))
503  {
504  ERROR("[ERROR] Failed fetching from vdso_image_x32 %llx: 0x%08x\n", vdsoImage, status);
505  return status;
506  }
507 
508  status = IntKernVirtMemFetchQword(vdsoImage + sizeof(QWORD), &vdsoSize);
509  if (!INT_SUCCESS(status))
510  {
511  ERROR("[ERROR] Failed fetching from vdso_image_x32 %llx: 0x%08x\n", vdsoImage, status);
512  return status;
513  }
514 
515  if (vdsoSize > 2 * PAGE_SIZE)
516  {
517  WARNING("[WARNING] vdso size is too large: %llu!\n", vdsoSize);
518  vdsoSize = 2 * PAGE_SIZE;
519  }
520 
522  }
523  else
524  {
525  gLixGuest->Vdso.VdsoStart = IntKsymFindByName("vdso_start", NULL);
526  if (!gLixGuest->Vdso.VdsoStart)
527  {
528  WARNING("[WARNING] 'vdso_start' not found\n");
529  return INT_STATUS_NOT_FOUND;
530  }
531 
532  gLixGuest->Vdso.VdsoEnd = IntKsymFindByName("vdso_end", NULL);
533  if (!gLixGuest->Vdso.VdsoEnd)
534  {
535  WARNING("[WARNING] 'vdso_end' not found\n");
536  return INT_STATUS_NOT_FOUND;
537  }
538 
539  gLixGuest->Vdso.Vdso32Start = IntKsymFindByName("vdsox32_start", NULL);
540  if (!gLixGuest->Vdso.Vdso32Start)
541  {
542  LOG("[INFO] Guest has been built without x32 ABI support!\n");
543  status = INT_STATUS_SUCCESS;
544  goto _exit;
545  }
546 
547  gLixGuest->Vdso.Vdso32End = IntKsymFindByName("vdsox32_end", NULL);
548  if (!gLixGuest->Vdso.Vdso32End)
549  {
550  WARNING("[WARNING] 'vdso_end_x32' not found\n");
551  status = INT_STATUS_SUCCESS;
552  goto _exit;
553  }
554  }
555 
556  status = INT_STATUS_SUCCESS;
557 
558 _exit:
559  return status;
560 }
561 
562 
563 static INTSTATUS
565  void
566  )
579 {
580  INTSTATUS status = INT_STATUS_SUCCESS;
581  QWORD vdsoStart = 0;
582  QWORD vdsoEnd = 0;
583  DWORD index;
584  LIX_TASK_OBJECT *pTask;
585 
586  for (DWORD i = 0; i < ARRAYSIZE(gVdsoGpaHook); i++)
587  {
588  if (gVdsoGpaHook[i] != NULL)
589  {
591  }
592  }
593 
594  pTask = IntLixTaskFindByPid(1);
595  if (pTask == NULL)
596  {
597  LOG("[LIX-VDSO] Will protect the vdso later...\n");
599  }
600 
601  status = IntLixVdsoFetchAddress(pTask, &vdsoStart);
602  if (!INT_SUCCESS(status))
603  {
604  ERROR("[ERROR] IntLixVdsoFetchAddress failed with status: 0x%08x.\n", status);
606  }
607 
608  vdsoEnd = vdsoStart + (gLixGuest->Vdso.VdsoEnd - gLixGuest->Vdso.VdsoStart);
609 
610  index = 0;
611  for (QWORD current = vdsoStart & PAGE_MASK; (current < vdsoEnd) &&
612  (index < ARRAYSIZE(gVdsoGpaHook)); current += PAGE_SIZE)
613  {
614  QWORD physAddr;
615  status = IntTranslateVirtualAddress(current, pTask->Cr3, &physAddr);
616  if (!INT_SUCCESS(status))
617  {
618  WARNING("[WARNING] IntTranslateVirtualAddress failed with status: 0x%08x. Will retry later...\n", status);
620  }
621 
622  status = IntHookGpaSetHook(physAddr,
623  PAGE_SIZE,
626  (void *)(introObjectTypeVdso),
627  0,
628  0,
629  (HOOK_GPA **)(&gVdsoGpaHook[index]));
630 
631  if (!INT_SUCCESS(status))
632  {
633  ERROR("[ERROR] IntHookGpaSetHook failed: 0x%08x\n", status);
634  return status;
635  }
636  index++;
637 
638  TRACE("[LIX-VDSO] Protecting VDSO physical page: 0x%llx.\n", physAddr);
639  }
640 
641  return INT_STATUS_SUCCESS;
642 }
643 
644 
645 static INTSTATUS
647  void
648  )
657 {
658  INTSTATUS status = INT_STATUS_SUCCESS;
659  QWORD hookSize = 0;
660 
661  if (NULL == gVdsoHook)
662  {
664  if (!INT_SUCCESS(status))
665  {
666  ERROR("[ERROR] IntHookObjectCreate failed: 0x%08x\n", status);
667  return status;
668  }
669  }
670 
672 
674  {
676  }
677 
679  0,
681  hookSize,
684  (void *)(introObjectTypeVdso),
685  0,
686  NULL);
687  if (!INT_SUCCESS(status))
688  {
689  ERROR("[ERROR] Failed setting hook on vdso: 0x%08x!\n", status);
690  gVdsoHook = NULL;
691 
692  return status;
693  }
694 
695  TRACE("[INFO] Protected vdso %llx -> %llx\n", gLixGuest->Vdso.VdsoStart, gLixGuest->Vdso.VdsoEnd);
696 
698  {
700 
702  0,
704  hookSize,
707  (void *)(introObjectTypeVdso),
708  0,
709  NULL);
710  if (!INT_SUCCESS(status))
711  {
712  ERROR("[ERROR] Failed setting hook on vdso: 0x%08x!\n", status);
713  gVdsoHook = NULL;
714 
715  return status;
716  }
717 
718  TRACE("[INFO] Protected vdso_32 %llx -> %llx\n", gLixGuest->Vdso.Vdso32Start, gLixGuest->Vdso.Vdso32End);
719  }
720 
721  return status;
722 }
723 
724 
725 INTSTATUS
727  void
728  )
738 {
739  INTSTATUS status = INT_STATUS_SUCCESS;
740 
742  {
744  }
745  else
746  {
748  }
749 
751  {
752  return INT_STATUS_SUCCESS;
753  }
754 
755  if (!INT_SUCCESS(status))
756  {
757  ERROR("[ERROR] Failed to protect the vdso...\n");
758  return status;
759  }
760 
761  gInitVdsoSym.Start = IntKsymFindByName("init_vdso", &gInitVdsoSym.End);
762  if (!gInitVdsoSym.Start)
763  {
764  WARNING("[WARNING] Failed finding 'init_vdso'. Some FPs may follow\n");
765  gInitVdsoSym.Start = gInitVdsoSym.End = 0;
766  }
767 
768  gTextPokeEarlySym.Start = IntKsymFindByName("text_poke_early", &gTextPokeEarlySym.End);
769  if (!gTextPokeEarlySym.Start)
770  {
771  WARNING("[WARNING] Failed finding 'text_poke_early'. Some FPs may follow\n");
772  gTextPokeEarlySym.Start = gTextPokeEarlySym.End = 0;
773  }
774 
775  gAddNopsSym.Start = IntKsymFindByName("add_nops", &gAddNopsSym.End);
776  if (!gAddNopsSym.Start)
777  {
778  WARNING("[WARNING] Failed finding 'add_nops'. Some FPs may follow\n");
779  gAddNopsSym.Start = gAddNopsSym.End = 0;
780  }
781 
782  return INT_STATUS_SUCCESS;
783 }
784 
785 
786 static INTSTATUS
788  void
789  )
798 {
799  INTSTATUS status;
800  QWORD vdsoPhys;
801 
802  if (!LIX_FIELD(Info, HasVdsoFixed))
803  {
804  TRACE("[INFO] This kernel is built without VSYSCALL support!");
806  }
807 
809  if (!INT_SUCCESS(status))
810  {
811  LOG("[INFO] Fixed VDSO is not present @ 0x%016llx (0x%08x)\n", LIX_VDSO_FIXED, status);
812  return status;
813  }
814 
815  if (NULL == gVdsoHook)
816  {
818  if (!INT_SUCCESS(status))
819  {
820  ERROR("[ERROR] IntHookObjectCreate failed with status: 0x%08x\n", status);
821  return status;
822  }
823  }
824 
826 
828  0,
830  PAGE_SIZE,
833  (void *)(introObjectTypeVsyscall),
834  0,
835  NULL);
836  if (!INT_SUCCESS(status))
837  {
838  ERROR("[ERROR] Failed setting hook on vsyscall with status: 0x%08x\n", status);
839  }
840  else
841  {
842  TRACE("[INFO] Protected VSYSCALL @ 0x%016llx\n", LIX_VDSO_FIXED);
843  }
844 
845  return status;
846 }
847 
848 
849 INTSTATUS
851  _In_ LIX_TASK_OBJECT *Task,
852  _Out_ QWORD *Address
853  )
863 {
864  INTSTATUS status = INT_STATUS_SUCCESS;
865 
866  if (Task == NULL)
867  {
869  }
870 
871  status = IntKernVirtMemFetchQword(Task->MmGva + LIX_FIELD(MmStruct, VdsoAddress), Address);
872  if (!INT_SUCCESS(status))
873  {
874  ERROR("[ERROR] IntKernVirtMemFetchQword failed with status: 0x%08x.\n", status);
875  return status;
876  }
877 
878  return INT_STATUS_SUCCESS;
879 }
880 
881 
882 INTSTATUS
884  void
885  )
891 {
892  INTSTATUS status = INT_STATUS_SUCCESS;
893 
894  if (NULL != gVdsoHook)
895  {
897  }
898 
899  status = IntLixVdsoFixedProtect();
900  if (!INT_SUCCESS(status))
901  {
902  WARNING("[WARNING] IntLixVdsoFixedProtect failed: 0x%08x\n", status);
903  }
904 
906  if (!INT_SUCCESS(status))
907  {
908  ERROR("[ERROR] IntLixVdsoResolveDynamicOffset failed with status: 0x%08x.\n", status);
909  return status;
910  }
911 
912  status = IntLixVdsoDynamicProtect();
913  if (INT_STATUS_NOT_FOUND == status)
914  {
915  WARNING("[WARNING] Dynamic VDSO cannot be protected for this guest\n");
916  }
917  else if (!INT_SUCCESS(status))
918  {
919  ERROR("[ERROR] IntLixVdsoDynamicProtect failed: 0x%08x\n", status);
920  return status;
921  }
922 
923  return INT_STATUS_SUCCESS;
924 }
925 
926 
927 void
929  void
930  )
934 {
935  if (NULL != gVdsoHook)
936  {
938  }
939 
940  for (DWORD index = 0; index < ARRAYSIZE(gVdsoGpaHook); index++)
941  {
942  if (gVdsoGpaHook[index] != NULL)
943  {
944  INTSTATUS status = IntHookGpaDeleteHook((HOOK_GPA **)(&gVdsoGpaHook[index]), 0);
945  if (!INT_SUCCESS(status))
946  {
947  ERROR("[ERROR] IntHookGpaDeleteHook failed with status: 0x%08x\n", status);
948  }
949  }
950  }
951 }
Measures kernel mode exceptions checks.
Definition: stats.h:51
#define _In_opt_
Definition: intro_sal.h:16
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
_Bool BOOLEAN
Definition: intro_types.h:58
#define _Out_
Definition: intro_sal.h:22
QWORD Cr3
The CR3 for this process.
Definition: lixprocess.h:70
static void IntLixVdsoHandleUserModeWrite(QWORD Address, INTRO_OBJECT_TYPE Type, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason)
Handles vDSO modification (from user-mode) detected by the EPT mechanism.
Definition: lixvdso.c:88
#define ALIGN_UP(x, a)
Definition: introdefs.h:164
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
QWORD End
The end guest virtual address of ksym (exclusive).
Definition: lixguest.h:439
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
BYTE Violation
The type of the access. It must be one of the IG_EPT_HOOK_TYPE values.
Definition: intro_types.h:1265
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
static LIX_SYMBOL gAddNopsSym
Definition: lixvdso.c:20
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
Measures user mode exceptions checks.
Definition: stats.h:50
static void * gVdsoHook
Definition: lixvdso.c:15
#define STATS_EXIT(id)
Definition: stats.h:160
INTSTATUS IntLixStackTraceGetReg(QWORD Cr3, PIG_ARCH_REGS Registers, DWORD MaxNumberOfTraces, QWORD Flags, STACK_TRACE *StackTrace)
Retrieves a Kernel stack backtrace based on the register values.
Definition: lixstack.c:225
User-mode exception.
Definition: exceptions.h:60
QWORD Start
The start guest virtual address of ksym.
Definition: lixguest.h:438
QWORD HookStartPhysical
The start of the monitored guest physical memory area for which this alert was generated.
Definition: intro_types.h:1270
#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
Structure that describes a stack trace element.
Definition: guest_stack.h:25
QWORD Vdso32Start
The guest virtual address where the vDSO x32 starts.
Definition: lixguest.h:522
#define INT_STATUS_NOT_NEEDED_HINT
Definition: introstatus.h:317
DWORD NumberOfTraces
Number of elements inside Traces.
Definition: guest_stack.h:44
#define ERROR(fmt,...)
Definition: glue.h:62
Describes a user-mode originator.
Definition: exceptions.h:994
struct _EVENT_EPT_VIOLATION::@283 Originator
INTSTATUS IntLixVdsoFetchAddress(LIX_TASK_OBJECT *Task, QWORD *Address)
Fetch the guest virtual address of the vDSO mapped on the provided task.
Definition: lixvdso.c:850
int INTSTATUS
The status data type.
Definition: introstatus.h:24
QWORD Vdso32End
The guest virtual address where the vDSO x32 end.
Definition: lixguest.h:523
void IntLixVdsoUnprotect(void)
Remove protection for the vDSO image and VSYSCALL.
Definition: lixvdso.c:928
#define INT_STATUS_NOT_FOUND
Definition: introstatus.h:284
Describes a kernel-mode originator.
Definition: exceptions.h:943
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
static INTSTATUS IntLixVdsoResolveImageAddress(char *FunctionName, QWORD *Address)
Parse the provided function and search the &#39;vdso_image...&#39; address.
Definition: lixvdso.c:331
STACK_ELEMENT * Traces
Array describing the stack trace elements.
Definition: guest_stack.h:46
QWORD HookStartVirtual
The start of the monitored guest virtual memory area for which this alert was generated.
Definition: intro_types.h:1268
EVENT_EPT_VIOLATION Ept
Definition: alerts.h:16
#define INTRO_OPT_PROT_KM_VDSO
Enable vDSO image protection (Linux only).
Definition: intro_types.h:500
void * IntHookObjectFindRegion(QWORD Gva, void *HookObject, BYTE HookType)
Searches for a region of hooked memory inside the provided hook object.
Definition: hook_object.c:424
INTSTATUS IntHookGpaSetHook(QWORD Gpa, DWORD Length, BYTE Type, PFUNC_EptViolationCallback Callback, void *Context, void *ParentHook, DWORD Flags, HOOK_GPA **Hook)
Places an EPT hook on the indicated memory range.
Definition: hook_gpa.c:193
#define LOG(fmt,...)
Definition: glue.h:61
Describes a kernel driver.
Definition: drivers.h:30
void IntAlertFillVersionInfo(INTRO_VIOLATION_HEADER *Header)
Fills version information for an alert.
Definition: alerts.c:327
static INTSTATUS IntLixVdsoHandleWrite(void *Context, void *Hook, QWORD Address, INTRO_ACTION *Action)
Handles vDSO modification detected by the EPT mechanism.
Definition: lixvdso.c:279
INTRO_VIOLATION_HEADER Header
The alert header.
Definition: intro_types.h:1217
QWORD ZoneTypes
The types of the accessed memory area.
Definition: intro_types.h:1276
INTRO_ACTION_REASON Reason
The reason for which Action was taken.
Definition: intro_types.h:1195
EXCEPTION_VICTIM_OBJECT Object
The modified object.
Definition: exceptions.h:895
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.
void IntAlertFillLixKmModule(const KERNEL_DRIVER *Driver, INTRO_MODULE *EventModule)
Saves information about a kernel module inside an alert.
Definition: alerts.c:1235
static LIX_SYMBOL gInitVdsoSym
Definition: lixvdso.c:19
#define LIX_VDSO_GPA_HOOK_PAGE_COUNT
Definition: lixvdso.c:13
static INTSTATUS IntLixVdsoDynamicProtectRelocate(void)
Protect the vDSO using GPA hooks.
Definition: lixvdso.c:564
#define ZONE_LIB_CODE
Used for a generic code zone.
Definition: exceptions.h:723
static BOOLEAN IntLixVdsoIsInitWrite(QWORD Rip)
Checks if the write is over the vDSO on the initialization phase.
Definition: lixvdso.c:257
#define INT_STATUS_EXCEPTION_BLOCK
Definition: introstatus.h:421
#define IS_KERNEL_POINTER_LIX(p)
Definition: lixguest.h:11
INTSTATUS IntKernVirtMemFetchQword(QWORD GuestVirtualAddress, QWORD *Data)
Reads 8 bytes from the guest kernel memory.
Definition: introcore.c:811
#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
void IntExceptUserLogInformation(EXCEPTION_VICTIM_ZONE *Victim, EXCEPTION_UM_ORIGINATOR *Originator, INTRO_ACTION Action, INTRO_ACTION_REASON Reason)
Print the information about a user-mode violation, dumps the code-blocks and the injection buffer...
INTSTATUS IntTranslateVirtualAddress(QWORD Gva, QWORD Cr3, QWORD *PhysicalAddress)
Translates a guest virtual address to a guest physical address.
Definition: introcore.c:1999
#define TRUE
Definition: intro_types.h:30
static LIX_SYMBOL gTextPokeEarlySym
Definition: lixvdso.c:21
#define LIX_FIELD(Structure, Field)
Macro used to access fields inside the LIX_OPAQUE_FIELDS structure.
Definition: lixguest.h:429
#define TRACE(fmt,...)
Definition: glue.h:58
QWORD VdsoEnd
The guest virtual address where the vDSO ends.
Definition: lixguest.h:520
QWORD ReturnAddress
The address where the current stack frame will return (@ ret)
Definition: guest_stack.h:34
INTSTATUS IntHookGpaDeleteHook(HOOK_GPA **Hook, DWORD Flags)
Permanently delete a GPA hook.
Definition: hook_gpa.c:830
DWORD NameHash
The hash of the modified object.
Definition: exceptions.h:854
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
INTRO_OBJECT_TYPE Type
The type of the modified object.
Definition: exceptions.h:852
INTRO_EXEC_CONTEXT ExecContext
Information about the instruction that triggered the alert.
Definition: intro_types.h:1309
#define INT_STATUS_ALREADY_INITIALIZED_HINT
Definition: introstatus.h:323
#define WARNING(fmt,...)
Definition: glue.h:60
INTSTATUS IntExceptUserGetOriginator(void *Process, BOOLEAN ModuleWrite, QWORD Address, INSTRUX *Instrux, EXCEPTION_UM_ORIGINATOR *Originator)
This function is used to get the information about the user-mode originator.
Sent when an EPT violation triggers an alert. See EVENT_EPT_VIOLATION.
Definition: intro_types.h:84
#define ALERT_FLAG_NOT_RING0
If set, the alert was triggered in ring 1, 2 or 3.
Definition: intro_types.h:674
Hooking.
Definition: intro_types.h:1154
static INTSTATUS IntLixVdsoDynamicProtectNonRelocate(void)
Protect the vDSO using GVA hooks.
Definition: lixvdso.c:646
static void IntLixVdsoHandleKernelModeWrite(QWORD Address, INTRO_OBJECT_TYPE Type, INTRO_ACTION *Action, INTRO_ACTION_REASON *Reason)
Handles vDSO modification (from kernel-mode) detected by the EPT mechanism.
Definition: lixvdso.c:26
#define PAGE_SIZE
Definition: common.h:70
Describes the modified zone.
Definition: exceptions.h:893
#define __forceinline
Definition: introtypes.h:61
uint32_t DWORD
Definition: intro_types.h:49
QWORD DataEnd
The guest virtual address where the data ends.
Definition: lixguest.h:501
enum _INTRO_ACTION INTRO_ACTION
Event actions.
The name is the operating system vdso (valid only for Linux).
Definition: exceptions.h:689
#define SIGN_EX_32(x)
Definition: introdefs.h:202
QWORD RoDataEnd
The guest virtual address where the read-only data ends.
Definition: lixguest.h:504
DWORD Offset
The offset inside the page where the violation took place.
Definition: intro_types.h:1274
#define MAX(a, b)
Definition: introdefs.h:151
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
Definition: guests.h:374
static void * gVdsoGpaHook[LIX_VDSO_GPA_HOOK_PAGE_COUNT]
Definition: lixvdso.c:16
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
struct _LINUX_GUEST::@127 Vdso
QWORD Vsyscall
The guest virtual address of the vsyscall.
Definition: lixguest.h:517
Virtual SYSCALL (user-mode, Linux-only).
Definition: intro_types.h:257
The name is the operating system vsyscall (valid only for Linux).
Definition: exceptions.h:690
#define LIX_VDSO_FIXED
Definition: lixvdso.h:12
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
QWORD VirtualPage
The guest virtual page in which the access was made.
Definition: intro_types.h:1272
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
Virtual dynamic shared object (user-mode, Linux-only).
Definition: intro_types.h:256
#define INT_STATUS_NOT_INITIALIZED_HINT
Definition: introstatus.h:320
#define INT_STATUS_INVALID_PARAMETER_1
Definition: introstatus.h:62
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
LIX_TASK_OBJECT * IntLixTaskGetCurrent(DWORD CpuNumber)
Finds the task that is currently running on the given CPU.
Definition: lixprocess.c:858
INTRO_MODULE Module
The module that did the malicious access.
Definition: intro_types.h:1221
64-bit selector.
Definition: glueiface.h:188
Holds register state.
Definition: glueiface.h:30
Event structure for EPT violations.
Definition: intro_types.h:1215
Structure that describes a stack trace.
Definition: guest_stack.h:42
void IntAlertFillLixCurrentProcess(INTRO_PROCESS *EventProcess)
Saves the current Linux process inside an event.
Definition: alerts.c:1310
Describes a Linux ksym.
Definition: lixguest.h:436
LIX_TASK_OBJECT * IntLixTaskFindByPid(DWORD Pid)
Finds the Linux process having the provided PID.
Definition: lixprocess.c:1051
QWORD IntKsymFindByName(const char *Name, QWORD *SymEnd)
Searches the given Name in kallsyms and returns the Start & End offset.
Definition: lixksym.c:1399
QWORD VdsoStart
The guest virtual address where the vDSO starts.
Definition: lixguest.h:519
INTSTATUS IntLixVdsoProtect(void)
Activates protection for the vDSO image and VSYSCALL.
Definition: lixvdso.c:883
Write-access hook.
Definition: glueiface.h:299
#define PAGE_MASK
Definition: pgtable.h:35
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 IntDecDecodeInstruction(IG_CS_TYPE CsType, QWORD Gva, void *Instrux)
Decode an instruction from the provided guest linear address.
Definition: decoder.c:180
static INTSTATUS IntLixVdsoHandleWriteCommon(void *Context, HOOK_GPA *Hook, QWORD Address, INTRO_ACTION *Action)
Handles vDSO modification detected by the EPT mechanism.
Definition: lixvdso.c:164
INTSTATUS IntHookObjectCreate(DWORD ObjectType, QWORD Cr3, void **Object)
Create a new hook object.
Definition: hook_object.c:81
static INTSTATUS IntLixVdsoFixedProtect(void)
This function activates the protection for the VSYSCALL.
Definition: lixvdso.c:787
static INTSTATUS IntLixVdsoResolveDynamicOffset(void)
Fetch the address of the &#39;vdso_image_64&#39;, &#39;vdso_image_x32&#39; ksyms or the address of the &#39;vdso_start&#39;...
Definition: lixvdso.c:433
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_OBJECT_TYPE Type
The type of the accessed memory area.
Definition: intro_types.h:1237
QWORD PhysicalPage
The guest physical page in which the access was made.
Definition: intro_types.h:1273
#define FALSE
Definition: intro_types.h:34
INTSTATUS IntLixVdsoDynamicProtect(void)
This function activates the protection for the vDSO image.
Definition: lixvdso.c:726