Bitdefender Hypervisor Memory Introspection
hook_msr.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 Bitdefender
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 #include "hook_msr.h"
6 #include "callbacks.h"
7 #include "guests.h"
8 
9 
12  _In_ DWORD Msr,
13  _In_ DWORD Flags,
15  _In_opt_ void *Context,
16  _Out_opt_ void **Hook
17  )
35 {
37  BOOLEAN bWasEnabled = FALSE, bOldValue = FALSE, bFound = FALSE;
38 
39  if (Callback == NULL)
40  {
42  }
43 
45  {
46  // We must skip disabled MSRs. MSR exit for this MSR may have been disabled already of the MSR hook is disabled.
47  if ((pListHook->Msr == Msr) && (!pListHook->Disabled))
48  {
49  bWasEnabled = pListHook->WasEnabled;
50 
51  bFound = TRUE;
52 
53  break;
54  }
55  }
56 
57  HOOK_MSR *pHook = HpAllocWithTag(sizeof(*pHook), IC_TAG_MSRHK);
58  if (NULL == pHook)
59  {
61  }
62 
63  pHook->Context = Context;
64  pHook->Msr = Msr;
65  pHook->Flags = Flags;
66  pHook->Callback = Callback;
67 
68  if (!bFound)
69  {
70  status = IntEnableMsrExit(Msr, &bOldValue);
71  if (!INT_SUCCESS(status))
72  {
73  ERROR("[ERROR] IntEnableMsrExit failed: 0x%08x\n", status);
74  }
75  }
76 
77  if (bFound)
78  {
79  pHook->WasEnabled = bWasEnabled;
80  }
81  else
82  {
83  pHook->WasEnabled = bOldValue;
84  }
85 
86  if (0 == gGuest.MsrHooks->HooksCount++)
87  {
88  status = IntEnableMsrNotifications();
89  if (!INT_SUCCESS(status))
90  {
92  return status;
93  }
94  }
95 
97 
98  if (NULL != Hook)
99  {
100  *Hook = pHook;
101  }
102 
103  return status;
104 }
105 
106 
107 static INTSTATUS
109  _In_ HOOK_MSR *Hook
110  )
120 {
121  if (!Hook->Disabled)
122  {
124  }
125 
127 
128  if (0 >= --gGuest.MsrHooks->HooksCount)
129  {
131  }
132 
133  return INT_STATUS_SUCCESS;
134 }
135 
136 
137 INTSTATUS
139  _In_ HOOK_MSR *Hook
140  )
154 {
155  INTSTATUS status;
156 
157  if (NULL == Hook)
158  {
160  }
161 
162  Hook->Disabled = TRUE;
163 
164  BOOLEAN bDisable = TRUE;
166  {
167  if ((Hook->Msr == pHook->Msr) && (pHook != Hook) && (!pHook->Disabled))
168  {
169  bDisable = FALSE;
170  }
171  }
172 
173  if (bDisable)
174  {
175  bDisable = !Hook->WasEnabled;
176  }
177 
178  if (bDisable)
179  {
180  // We deactivate MSR exiting for this MSR only if it was deactivated before we activated it.
181  status = IntDisableMsrExit(Hook->Msr, &bDisable);
182  if (!INT_SUCCESS(status))
183  {
184  ERROR("[ERROR] IntDisableMsrExit failed: 0x%08x\n", status);
185  }
186  }
187 
188  // If we're not handling a MSR violation right now then we can safely delete the MSR hook.
190  {
191  RemoveEntryList(&Hook->Link);
192 
193  status = IntHookMsrDeleteHook(Hook);
194  if (!INT_SUCCESS(status))
195  {
196  ERROR("[ERROR] IntHookMsrDeleteHook failed: 0x%08x\n", status);
197  }
198  }
199 
200  return INT_STATUS_SUCCESS;
201 }
202 
203 
204 static void
206  void
207  )
211 {
213  {
214  INTSTATUS status = IntHookMsrRemoveHook(pHook);
215  if (!INT_SUCCESS(status))
216  {
217  ERROR("[ERROR] IntHookMsrRemoveHook failed: 0x%08x\n", status);
218  }
219  }
220 }
221 
222 
223 INTSTATUS
225  void
226  )
235 {
236  INTSTATUS status = INT_STATUS_SUCCESS;
237 
238  if (NULL == gGuest.MsrHooks)
239  {
241  }
242 
244  {
245  if (pHook->Disabled)
246  {
247  RemoveEntryList(&pHook->Link);
248 
249  status = IntHookMsrDeleteHook(pHook);
250  if (!INT_SUCCESS(status))
251  {
252  ERROR("[ERROR] IntHookMsrDeleteHook failed: 0x%08x\n", status);
253  }
254  }
255  }
256 
257  return status;
258 }
259 
260 
261 INTSTATUS
263  void
264  )
271 {
273  if (NULL == gGuest.MsrHooks)
274  {
276  }
277 
279 
280  return INT_STATUS_SUCCESS;
281 }
282 
283 
284 INTSTATUS
286  void
287  )
294 {
295  if (NULL == gGuest.MsrHooks)
296  {
298  }
299 
301 
303 
304  return INT_STATUS_SUCCESS;
305 }
#define _In_opt_
Definition: intro_sal.h:16
_Bool BOOLEAN
Definition: intro_types.h:58
Handling MSR violation.
Definition: guests.h:23
#define _In_
Definition: intro_sal.h:21
#define INT_STATUS_SUCCESS
Definition: introstatus.h:54
PFUNC_MsrReadWriteHookCallback Callback
The callback.
Definition: hook_msr.h:53
INTSTATUS IntHookMsrUninit(void)
Uninit the model specific register hooks state.
Definition: hook_msr.c:285
#define INT_SUCCESS(Status)
Definition: introstatus.h:42
#define ERROR(fmt,...)
Definition: glue.h:62
#define HpAllocWithTag(Len, Tag)
Definition: glue.h:516
int INTSTATUS
The status data type.
Definition: introstatus.h:24
LIST_ENTRY Link
List entry element.
Definition: hook_msr.h:48
INT64 HooksCount
Total number of MSR hooks.
Definition: hook_msr.h:39
INTSTATUS IntEnableMsrExit(DWORD Msr, BOOLEAN *OldValue)
Definition: glue.c:499
MSR_HOOK_STATE * MsrHooks
MSR hook state.
Definition: guests.h:387
static void IntHookMsrRemoveAllHooks(void)
Remove all model specific register write hooks.
Definition: hook_msr.c:205
#define _Out_opt_
Definition: intro_sal.h:30
#define INT_STATUS_NOT_INITIALIZED
Definition: introstatus.h:266
static BOOLEAN RemoveEntryList(LIST_ENTRY *Entry)
Definition: introlists.h:87
CPU_STATE State
The state of this VCPU. Describes what action is the VCPU currently doing.
Definition: guests.h:173
#define TRUE
Definition: intro_types.h:30
#define IC_TAG_MSRS
MSR hook state.
Definition: memtags.h:69
#define HpFreeAndNullWithTag(Add, Tag)
Definition: glue.h:517
static void InsertTailList(LIST_ENTRY *ListHead, LIST_ENTRY *Entry)
Definition: introlists.h:135
static INTSTATUS IntEnableMsrNotifications(void)
Definition: callbacks.h:159
LIST_HEAD MsrHooksList
The list of MSR hooks.
Definition: hook_msr.h:38
static INTSTATUS IntHookMsrDeleteHook(HOOK_MSR *Hook)
Permanently delete a model specific register hook.
Definition: hook_msr.c:108
static void InitializeListHead(LIST_ENTRY *ListHead)
Definition: introlists.h:69
#define IC_TAG_MSRHK
MSR Hook descriptor.
Definition: memtags.h:32
INTSTATUS IntHookMsrRemoveHook(HOOK_MSR *Hook)
Remove a model specific register hook.
Definition: hook_msr.c:138
uint32_t DWORD
Definition: intro_types.h:49
INTSTATUS IntHookMsrSetHook(DWORD Msr, DWORD Flags, PFUNC_MsrReadWriteHookCallback Callback, void *Context, void **Hook)
Set a model-specific register write hook.
Definition: hook_msr.c:11
DWORD Msr
The hooked MSR.
Definition: hook_msr.h:49
BOOLEAN WasEnabled
True if MSR exiting for this MSR was already enabled.
Definition: hook_msr.h:51
GUEST_STATE gGuest
The current guest state.
Definition: guests.c:50
INTSTATUS(* PFUNC_MsrReadWriteHookCallback)(DWORD Msr, DWORD Flags, INTRO_ACTION *Action, void *Context, QWORD OriginalValue, QWORD *NewValue)
Model specific register access callback.
Definition: hook_msr.h:23
#define INT_STATUS_NOT_INITIALIZED_HINT
Definition: introstatus.h:320
#define INT_STATUS_INVALID_PARAMETER_1
Definition: introstatus.h:62
VCPU_STATE * gVcpu
The state of the current VCPU.
Definition: guests.c:59
#define list_for_each(_head, _struct_type, _var)
Definition: introlists.h:41
DWORD Flags
Access flags. See IG_MSR_HOOK_TYPE.
Definition: hook_msr.h:50
INTSTATUS IntHookMsrInit(void)
Initialize the model specific registers hook state.
Definition: hook_msr.c:262
void * Context
Optional context.
Definition: hook_msr.h:54
INTSTATUS IntHookMsrCommit(void)
Commit the model specific register hooks.
Definition: hook_msr.c:224
INTSTATUS IntDisableMsrExit(DWORD Msr, BOOLEAN *OldValue)
Definition: glue.c:509
#define FALSE
Definition: intro_types.h:34
#define INT_STATUS_INSUFFICIENT_RESOURCES
Definition: introstatus.h:281
#define INT_STATUS_INVALID_PARAMETER_3
Definition: introstatus.h:68
static INTSTATUS IntDisableMsrNotifications(void)
Definition: callbacks.h:176