test_vmxon_intel_x64.cpp
Go to the documentation of this file.
1 //
2 // Bareflank Hypervisor
3 //
4 // Copyright (C) 2015 Assured Information Security, Inc.
5 // Author: Rian Quinn <quinnr@ainfosec.com>
6 // Author: Brendan Kerrigan <kerriganb@ainfosec.com>
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 
22 #include <gsl/gsl>
23 
24 #include <test.h>
25 #include <vmxon/vmxon_intel_x64.h>
27 
28 #include <intrinsics/cpuid_x64.h>
29 #include <intrinsics/rflags_x64.h>
33 
34 using namespace x64;
35 using namespace intel_x64;
36 
37 static cr0::value_type g_cr0 = 0;
38 static cr4::value_type g_cr4 = 0;
39 static rflags::value_type g_rflags = 0;
40 static std::map<msrs::field_type, msrs::value_type> g_msrs;
41 static std::map<cpuid::field_type, cpuid::value_type> g_cpuid;
42 
43 bool g_vmxon_fails = false;
44 bool g_vmxoff_fails = false;
45 bool g_write_cr4_fails = false;
47 
48 extern "C" uint64_t
50 { return g_cr0; }
51 
52 extern "C" uint64_t
54 { return g_cr4; }
55 
56 extern "C" void
57 __write_cr4(uint64_t val) noexcept
58 {
60  return;
61 
62  g_cr4 = val;
63 }
64 
65 extern "C" uint64_t
67 { return g_msrs[addr]; }
68 
69 extern "C" void
70 __write_msr(uint32_t addr, uint64_t val) noexcept
71 { g_msrs[addr] = val; }
72 
73 extern "C" uint64_t
75 { return g_rflags; }
76 
77 extern "C" uint32_t
78 __cpuid_ecx(uint32_t val) noexcept
79 { return g_cpuid[val]; }
80 
81 extern "C" bool
82 __vmxon(void *ptr) noexcept
83 { (void) ptr; return !g_vmxon_fails; }
84 
85 extern "C" bool
87 { return !g_vmxoff_fails; }
88 
89 static uintptr_t
90 virtptr_to_physint(void *ptr)
91 {
92  (void) ptr;
93 
95  throw gsl::fail_fast("");
96 
97  return 0x0000000ABCDEF0000;
98 }
99 
100 static void
101 setup_intrinsics(MockRepository &mocks, memory_manager_x64 *mm)
102 {
103  g_cr0 = 0x0;
104  g_cr4 = 0x0;
105 
107  g_msrs[msrs::ia32_vmx_cr0_fixed1::addr] = 0xFFFFFFFFFFFFFFFF;
109  g_msrs[msrs::ia32_vmx_cr4_fixed1::addr] = 0xFFFFFFFFFFFFFFFF;
110 
111  g_msrs[msrs::ia32_vmx_basic::addr] = (1ULL << 55) | (6ULL << 50);
112  g_msrs[msrs::ia32_feature_control::addr] = (0x1ULL << 0);
114 
115  mocks.OnCallFunc(memory_manager_x64::instance).Return(mm);
116  mocks.OnCall(mm, memory_manager_x64::virtptr_to_physint).Do(virtptr_to_physint);
117 }
118 
119 void
120 vmxon_ut::test_start_success()
121 {
122  MockRepository mocks;
123  auto &&mm = mocks.Mock<memory_manager_x64>();
124 
125  setup_intrinsics(mocks, mm);
126 
127  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
128  {
130  this->expect_no_exception([&]{ vmxon.start(); });
131  });
132 }
133 
134 void
135 vmxon_ut::test_start_start_twice()
136 {
137  MockRepository mocks;
138  auto &&mm = mocks.Mock<memory_manager_x64>();
139 
140  setup_intrinsics(mocks, mm);
141 
142  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
143  {
145 
146  this->expect_no_exception([&]{ vmxon.start(); });
147  g_cr4 = 0;
148  this->expect_exception([&]{ vmxon.start(); }, ""_ut_lee);
149  });
150 }
151 
152 void
153 vmxon_ut::test_start_execute_vmxon_already_on_failure()
154 {
155  MockRepository mocks;
156  auto &&mm = mocks.Mock<memory_manager_x64>();
157 
158  setup_intrinsics(mocks, mm);
159 
161 
162  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
163  {
165  this->expect_exception([&]{ vmxon.start(); }, ""_ut_lee);
166  });
167 }
168 
169 void
170 vmxon_ut::test_start_execute_vmxon_failure()
171 {
172  MockRepository mocks;
173  auto &&mm = mocks.Mock<memory_manager_x64>();
174 
175  setup_intrinsics(mocks, mm);
176 
177  auto ___ = gsl::finally([&]
178  { g_vmxon_fails = false; });
179 
180  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
181  {
183 
184  g_vmxon_fails = true;
185  this->expect_exception([&]{ vmxon.start(); }, ""_ut_ree);
186  });
187 }
188 
189 void
190 vmxon_ut::test_start_check_ia32_vmx_cr4_fixed0_msr_failure()
191 {
192  MockRepository mocks;
193  auto &&mm = mocks.Mock<memory_manager_x64>();
194 
195  setup_intrinsics(mocks, mm);
196 
198 
199  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
200  {
202  this->expect_exception([&]{ vmxon.start(); }, ""_ut_lee);
203  });
204 }
205 
206 void
207 vmxon_ut::test_start_check_ia32_vmx_cr4_fixed1_msr_failure()
208 {
209  MockRepository mocks;
210  auto &&mm = mocks.Mock<memory_manager_x64>();
211 
212  setup_intrinsics(mocks, mm);
213 
214  g_cr4 = 0x1;
215  g_msrs[msrs::ia32_vmx_cr4_fixed1::addr] = 0xFFFFFFFFFFFFFFF0;
216 
217  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
218  {
220  this->expect_exception([&]{ vmxon.start(); }, ""_ut_lee);
221  });
222 }
223 
224 void
225 vmxon_ut::test_start_enable_vmx_operation_failure()
226 {
227  MockRepository mocks;
228  auto &&mm = mocks.Mock<memory_manager_x64>();
229 
230  setup_intrinsics(mocks, mm);
231 
232  g_write_cr4_fails = true;
233 
234  auto ___ = gsl::finally([&]
235  { g_write_cr4_fails = false; });
236 
237  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
238  {
240  this->expect_exception([&]{ vmxon.start(); }, ""_ut_lee);
241  });
242 }
243 
244 void
245 vmxon_ut::test_start_v8086_disabled_failure()
246 {
247  MockRepository mocks;
248  auto &&mm = mocks.Mock<memory_manager_x64>();
249 
250  setup_intrinsics(mocks, mm);
251 
252  g_rflags = 0xFFFFFFFFFFFFFFFF;
253 
254  auto ___ = gsl::finally([&]
255  { g_rflags = 0x0; });
256 
257  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
258  {
260  this->expect_exception([&]{ vmxon.start(); }, ""_ut_lee);
261  });
262 }
263 
264 void
265 vmxon_ut::test_start_check_ia32_feature_control_msr_lock_bit_clear()
266 {
267  MockRepository mocks;
268  auto &&mm = mocks.Mock<memory_manager_x64>();
269 
270  setup_intrinsics(mocks, mm);
271 
273 
274  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
275  {
277  this->expect_no_exception([&]{ vmxon.start(); });
278  });
279 
280 }
281 
282 void
283 vmxon_ut::test_start_check_ia32_feature_control_msr_lock_bit_set()
284 {
285  MockRepository mocks;
286  auto &&mm = mocks.Mock<memory_manager_x64>();
287 
288  setup_intrinsics(mocks, mm);
289 
291 
292  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
293  {
295  this->expect_no_exception([&]{ vmxon.start(); });
296  });
297 }
298 
299 void
300 vmxon_ut::test_start_check_ia32_vmx_cr0_fixed0_msr()
301 {
302  MockRepository mocks;
303  auto &&mm = mocks.Mock<memory_manager_x64>();
304 
305  setup_intrinsics(mocks, mm);
306 
308 
309  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
310  {
312  this->expect_exception([&]{ vmxon.start(); }, ""_ut_lee);
313  });
314 }
315 
316 void
317 vmxon_ut::test_start_check_ia32_vmx_cr0_fixed1_msr()
318 {
319  MockRepository mocks;
320  auto &&mm = mocks.Mock<memory_manager_x64>();
321 
322  setup_intrinsics(mocks, mm);
323 
324  g_cr0 = 0x1;
325  g_msrs[msrs::ia32_vmx_cr0_fixed1::addr] = 0xFFFFFFFFFFFFFFF0;
326 
327  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
328  {
330  this->expect_exception([&]{ vmxon.start(); }, ""_ut_lee);
331  });
332 }
333 
334 void
335 vmxon_ut::test_start_check_vmx_capabilities_msr_memtype_failure()
336 {
337  MockRepository mocks;
338  auto &&mm = mocks.Mock<memory_manager_x64>();
339 
340  setup_intrinsics(mocks, mm);
341 
342  g_msrs[msrs::ia32_vmx_basic::addr] = (1ULL << 55);
343 
344  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
345  {
347  this->expect_exception([&]{ vmxon.start(); }, ""_ut_lee);
348  });
349 }
350 
351 void
352 vmxon_ut::test_start_check_vmx_capabilities_msr_addr_width_failure()
353 {
354  MockRepository mocks;
355  auto &&mm = mocks.Mock<memory_manager_x64>();
356 
357  setup_intrinsics(mocks, mm);
358 
359  g_msrs[msrs::ia32_vmx_basic::addr] = (1ULL << 55) | (6ULL << 50) | (1ULL << 48);
360 
361  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
362  {
364  this->expect_exception([&]{ vmxon.start(); }, ""_ut_lee);
365  });
366 }
367 
368 void
369 vmxon_ut::test_start_check_vmx_capabilities_true_based_controls_failure()
370 {
371  MockRepository mocks;
372  auto &&mm = mocks.Mock<memory_manager_x64>();
373 
374  setup_intrinsics(mocks, mm);
375 
376  g_msrs[msrs::ia32_vmx_basic::addr] = (6ULL << 50);
377 
378  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
379  {
381  this->expect_exception([&]{ vmxon.start(); }, ""_ut_lee);
382  });
383 }
384 
385 void
386 vmxon_ut::test_start_check_cpuid_vmx_supported_failure()
387 {
388  MockRepository mocks;
389  auto &&mm = mocks.Mock<memory_manager_x64>();
390 
391  setup_intrinsics(mocks, mm);
392 
394 
395  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
396  {
398  this->expect_exception([&]{ vmxon.start(); }, ""_ut_lee);
399  });
400 }
401 
402 void
403 vmxon_ut::test_start_virt_to_phys_failure()
404 {
405  MockRepository mocks;
406  auto &&mm = mocks.Mock<memory_manager_x64>();
407 
408  setup_intrinsics(mocks, mm);
409 
410  auto ___ = gsl::finally([&]
411  { g_virt_to_phys_return_nullptr = false; });
412 
414 
415  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
416  {
418  this->expect_exception([&]{ vmxon.start(); }, ""_ut_ffe);
419  });
420 }
421 
422 void
423 vmxon_ut::test_stop_success()
424 {
425  MockRepository mocks;
426  auto &&mm = mocks.Mock<memory_manager_x64>();
427 
428  setup_intrinsics(mocks, mm);
429 
430  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
431  {
433 
434  vmxon.start();
435  this->expect_no_exception([&]{ vmxon.stop(); });
436  });
437 }
438 
439 void
440 vmxon_ut::test_stop_stop_twice()
441 {
442  MockRepository mocks;
443  auto &&mm = mocks.Mock<memory_manager_x64>();
444 
445  setup_intrinsics(mocks, mm);
446 
447  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
448  {
450 
451  vmxon.start();
452  this->expect_no_exception([&]{ vmxon.stop(); });
453  this->expect_no_exception([&]{ vmxon.stop(); });
454  });
455 }
456 
457 void
458 vmxon_ut::test_stop_vmxoff_check_failure()
459 {
460  MockRepository mocks;
461  auto &&mm = mocks.Mock<memory_manager_x64>();
462 
463  setup_intrinsics(mocks, mm);
464 
465  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
466  {
468  vmxon.start();
469 
470  g_write_cr4_fails = true;
471 
472  auto ___ = gsl::finally([&]
473  { g_write_cr4_fails = false; });
474 
475  this->expect_exception([&]{ vmxon.stop(); }, ""_ut_lee);
476  });
477 }
478 
479 void
480 vmxon_ut::test_stop_vmxoff_failure()
481 {
482  MockRepository mocks;
483  auto &&mm = mocks.Mock<memory_manager_x64>();
484 
485  setup_intrinsics(mocks, mm);
486 
487  auto ___ = gsl::finally([&]
488  { g_vmxoff_fails = false; });
489 
490  RUN_UNITTEST_WITH_MOCKS(mocks, [&]
491  {
493  vmxon.start();
494 
495  g_vmxoff_fails = true;
496  this->expect_exception([&]{ vmxon.stop(); }, ""_ut_ree);
497  });
498 }
#define expect_exception(f, e)
Definition: unittest.h:162
#define RUN_UNITTEST_WITH_MOCKS(a, b)
Definition: unittest.h:229
bool g_vmxoff_fails
cr0::value_type g_cr0
cr4::value_type g_cr4
#define expect_no_exception(f)
Definition: unittest.h:198
constexpr const auto mask
Definition: cpuid_x64.h:85
uint64_t g_cpuid
Definition: entry.c:48
bool __vmxon(void *ptr) noexcept
virtual integer_pointer virtptr_to_physint(pointer virt) const
uint64_t value_type
Definition: crs_intel_x64.h:46
void uint64_t uint64_t uint64_t *rdx noexcept
bool g_virt_to_phys_return_nullptr
constexpr const auto addr
Definition: cpuid_x64.h:80
std::map< msrs::field_type, msrs::value_type > g_msrs
uint32_t __cpuid_ecx(uint32_t val) noexcept
static memory_manager_x64 * instance() noexcept
uint64_t __read_rflags(void) noexcept
constexpr const auto addr
Definition: cpuid_x64.h:106
bool __vmxoff(void) noexcept
void __write_msr(uint32_t addr, uint64_t val) noexcept
void __write_cr4(uint64_t val) noexcept
bool g_vmxon_fails
uint64_t value_type
Definition: rflags_x64.h:39
uint64_t __read_msr(uint32_t addr) noexcept
uint64_t __read_cr4(void) noexcept
bool g_write_cr4_fails
uint64_t value_type
rflags::value_type g_rflags
Definition: cache_x64.h:31
uintptr_t virtptr_to_physint(void *ptr)
Definition: test.cpp:173
uint64_t __read_cr0(void) noexcept