exit_handler_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 <debug.h>
25 #include <constants.h>
26 #include <error_codes.h>
27 #include <guard_exceptions.h>
32 
33 #include <intrinsics/pm_x64.h>
34 #include <intrinsics/cache_x64.h>
35 #include <intrinsics/cpuid_x64.h>
37 
45 
46 using namespace x64;
47 using namespace intel_x64;
48 
49 #include <mutex>
51 
53  m_vmcs(nullptr),
54  m_state_save(nullptr)
55 { }
56 
57 void
59 { handle_exit(vmcs::exit_reason::basic_exit_reason::get()); }
60 
61 void
63 {
64  std::lock_guard<std::mutex> guard(g_unimplemented_handler_mutex);
65 
66  bferror << bfendl;
67  bferror << bfendl;
68  bferror << "Guest register state: " << bfendl;
69  bferror << "----------------------------------------------------" << bfendl;
70  bferror << "- m_state_save->rax: " << view_as_pointer(m_state_save->rax) << bfendl;
71  bferror << "- m_state_save->rbx: " << view_as_pointer(m_state_save->rbx) << bfendl;
72  bferror << "- m_state_save->rcx: " << view_as_pointer(m_state_save->rcx) << bfendl;
73  bferror << "- m_state_save->rdx: " << view_as_pointer(m_state_save->rdx) << bfendl;
74  bferror << "- m_state_save->rbp: " << view_as_pointer(m_state_save->rbp) << bfendl;
75  bferror << "- m_state_save->rsi: " << view_as_pointer(m_state_save->rsi) << bfendl;
76  bferror << "- m_state_save->rdi: " << view_as_pointer(m_state_save->rdi) << bfendl;
77  bferror << "- m_state_save->r08: " << view_as_pointer(m_state_save->r08) << bfendl;
78  bferror << "- m_state_save->r09: " << view_as_pointer(m_state_save->r09) << bfendl;
79  bferror << "- m_state_save->r10: " << view_as_pointer(m_state_save->r10) << bfendl;
80  bferror << "- m_state_save->r11: " << view_as_pointer(m_state_save->r11) << bfendl;
81  bferror << "- m_state_save->r12: " << view_as_pointer(m_state_save->r12) << bfendl;
82  bferror << "- m_state_save->r13: " << view_as_pointer(m_state_save->r13) << bfendl;
83  bferror << "- m_state_save->r14: " << view_as_pointer(m_state_save->r14) << bfendl;
84  bferror << "- m_state_save->r15: " << view_as_pointer(m_state_save->r15) << bfendl;
85  bferror << "- m_state_save->rip: " << view_as_pointer(m_state_save->rip) << bfendl;
86  bferror << "- m_state_save->rsp: " << view_as_pointer(m_state_save->rsp) << bfendl;
87 
88  bferror << bfendl;
89  bferror << bfendl;
90  bferror << "CPU Halted: " << bfendl;
91  bferror << "----------------------------------------------------" << bfendl;
92  bferror << "- vcpuid: " << m_state_save->vcpuid << bfendl;
93 
94  bferror << bfendl;
95  bferror << bfendl;
96 
98 
99  pm::stop();
100 }
101 
102 void
104 {
105  switch (reason)
106  {
108  handle_cpuid();
109  break;
110 
112  handle_invd();
113  break;
114 
116  handle_vmcall();
117  break;
118 
120  handle_vmxoff();
121  break;
122 
124  handle_rdmsr();
125  break;
126 
128  handle_wrmsr();
129  break;
130 
131  default:
133  break;
134  };
135 
136  m_vmcs->resume();
137 }
138 
139 void
141 {
142  auto ret = cpuid::get(m_state_save->rax,
143  m_state_save->rbx,
144  m_state_save->rcx,
145  m_state_save->rdx);
146 
147  m_state_save->rax = std::get<0>(ret);
148  m_state_save->rbx = std::get<1>(ret);
149  m_state_save->rcx = std::get<2>(ret);
150  m_state_save->rdx = std::get<3>(ret);
151 
152  advance_rip();
153 }
154 
155 void
157 {
158  cache::wbinvd();
159  advance_rip();
160 }
161 
162 void
164 {
165  auto &&regs = vmcall_registers_t{};
166 
167  switch (m_state_save->rax)
168  {
169  case VMCALL_EVENT:
170  regs.r02 = m_state_save->rcx;
171  break;
172 
173  default:
174  regs.r02 = m_state_save->rcx;
175  regs.r03 = m_state_save->rbx;
176  regs.r04 = m_state_save->rsi;
177  regs.r05 = m_state_save->r08;
178  regs.r06 = m_state_save->r09;
179  regs.r07 = m_state_save->r10;
180  regs.r08 = m_state_save->r11;
181  regs.r09 = m_state_save->r12;
182  regs.r10 = m_state_save->r13;
183  regs.r11 = m_state_save->r14;
184  regs.r12 = m_state_save->r15;
185  break;
186  };
187 
189  return complete_vmcall(BF_VMCALL_FAILURE, regs);
190 
191  auto &&ret = guard_exceptions(BF_VMCALL_FAILURE, [&]
192  {
193  switch (m_state_save->rax)
194  {
195  case VMCALL_VERSIONS:
196  handle_vmcall_versions(regs);
197  break;
198 
199  case VMCALL_REGISTERS:
200  handle_vmcall_registers(regs);
201  break;
202 
203  case VMCALL_DATA:
204  handle_vmcall_data(regs);
205  break;
206 
207  case VMCALL_EVENT:
208  handle_vmcall_event(regs);
209  break;
210 
211  case VMCALL_START:
212  handle_vmcall_start(regs);
213  break;
214 
215  case VMCALL_STOP:
216  handle_vmcall_stop(regs);
217  break;
218 
219  case VMCALL_UNITTEST:
220  handle_vmcall_unittest(regs);
221  break;
222 
223  default:
224  throw std::runtime_error("unknown vmcall opcode");
225  };
226  });
227 
228  complete_vmcall(ret, regs);
229 }
230 
231 void
234 {
235  switch (m_state_save->rax)
236  {
237  case VMCALL_EVENT:
238  m_state_save->rcx = regs.r02;
239  break;
240 
241  default:
242  m_state_save->r15 = regs.r12;
243  m_state_save->r14 = regs.r11;
244  m_state_save->r13 = regs.r10;
245  m_state_save->r12 = regs.r09;
246  m_state_save->r11 = regs.r08;
247  m_state_save->r10 = regs.r07;
248  m_state_save->r09 = regs.r06;
249  m_state_save->r08 = regs.r05;
250  m_state_save->rsi = regs.r04;
251  m_state_save->rbx = regs.r03;
252  m_state_save->rcx = regs.r02;
253  break;
254  };
255 
256  m_state_save->rdx = static_cast < decltype(m_state_save->rdx) > (ret);
257  advance_rip();
258 }
259 
260 void
262 { m_vmcs->promote(); }
263 
264 void
266 {
268 
269  switch (m_state_save->rcx)
270  {
272  msr = vmcs::guest_ia32_debugctl::get();
273  break;
274 
276  msr = vmcs::guest_ia32_pat::get();
277  break;
278 
280  msr = vmcs::guest_ia32_efer::get();
281  break;
282 
284  msr = vmcs::guest_ia32_perf_global_ctrl::get();
285  break;
286 
288  msr = vmcs::guest_ia32_sysenter_cs::get();
289  break;
290 
292  msr = vmcs::guest_ia32_sysenter_esp::get();
293  break;
294 
296  msr = vmcs::guest_ia32_sysenter_eip::get();
297  break;
298 
300  msr = vmcs::guest_fs_base::get();
301  break;
302 
304  msr = vmcs::guest_gs_base::get();
305  break;
306 
307  default:
309  break;
310 
311  // QUIRK:
312  //
313  // The following is specifically for CPU-Z. For whatever reason, it is
314  // reading the following undefined MSRs, which causes the system to
315  // freeze since attempting to read these MSRs in the exit handler
316  // will cause a GP which is not being caught. The result is, the core
317  // that runs RDMSR on these freezes, the other cores receive an
318  // INIT signal to reset, and the system dies.
319  //
320 
321  case 0x31:
322  case 0x39:
323  case 0x1ae:
324  case 0x1af:
325  case 0x602:
326  msr = 0;
327  break;
328  }
329 
330  m_state_save->rax = ((msr >> 0x00) & 0x00000000FFFFFFFF);
331  m_state_save->rdx = ((msr >> 0x20) & 0x00000000FFFFFFFF);
332 
333  advance_rip();
334 }
335 
336 void
338 {
340 
341  msr |= ((m_state_save->rax & 0x00000000FFFFFFFF) << 0x00);
342  msr |= ((m_state_save->rdx & 0x00000000FFFFFFFF) << 0x20);
343 
344  switch (m_state_save->rcx)
345  {
348  break;
349 
352  break;
353 
356  break;
357 
360  break;
361 
364  break;
365 
368  break;
369 
372  break;
373 
376  break;
377 
380  break;
381 
382  default:
384  break;
385  }
386 
387  advance_rip();
388 }
389 
390 void
392 { m_state_save->rip += vmcs::vm_exit_instruction_length::get(); }
393 
394 void
396 {
397  std::lock_guard<std::mutex> guard(g_unimplemented_handler_mutex);
398 
399  bferror << bfendl;
400  bferror << bfendl;
401  bferror << "Unimplemented Exit Handler: " << bfendl;
402  bferror << "----------------------------------------------------" << bfendl;
403  bferror << "- exit reason: "
404  << view_as_pointer(vmcs::exit_reason::get()) << bfendl;
405  bferror << "- exit reason string: "
407  bferror << "- exit qualification: "
408  << view_as_pointer(vmcs::exit_qualification::get()) << bfendl;
409  bferror << "- exit interrupt information: "
410  << view_as_pointer(vmcs::vm_exit_interruption_information::get()) << bfendl;
411  bferror << "- instruction length: "
412  << view_as_pointer(vmcs::vm_exit_instruction_length::get()) << bfendl;
413  bferror << "- instruction information: "
414  << view_as_pointer(vmcs::vm_exit_instruction_information::get()) << bfendl;
415  bferror << "- guest linear address: "
416  << view_as_pointer(vmcs::guest_linear_address::get()) << bfendl;
417  bferror << "- guest physical address: "
418  << view_as_pointer(vmcs::guest_physical_address::get()) << bfendl;
419 
421  {
422  bferror << bfendl;
423  bferror << "VM-entry failure detected!!!" << bfendl;
424  bferror << bfendl;
425 
426  guard_exceptions([&]
427  { vmcs::check::all(); });
428 
429  guard_exceptions([&]
430  { vmcs::debug::dump(); });
431  }
432 
434 
435  this->halt();
436 }
437 
438 void
440 {
441  switch (regs.r02)
442  {
444  regs.r03 = VMCALL_VERSION;
445  regs.r04 = 0;
446  regs.r05 = 0;
447  break;
448 
453  break;
454 
455  case VMCALL_VERSION_USER:
456  regs.r03 = USER_VERSION_MAJOR;
457  regs.r04 = USER_VERSION_MINOR;
458  regs.r05 = USER_VERSION_PATCH;
459  break;
460 
461  default:
462  throw std::runtime_error("unknown vmcall version index");
463  }
464 }
465 
466 void
468 {
469  bfdebug << "vmcall registers:" << bfendl;
470  bfdebug << "r02: " << view_as_pointer(regs.r02) << bfendl;
471  bfdebug << "r03: " << view_as_pointer(regs.r03) << bfendl;
472  bfdebug << "r04: " << view_as_pointer(regs.r04) << bfendl;
473  bfdebug << "r05: " << view_as_pointer(regs.r05) << bfendl;
474  bfdebug << "r06: " << view_as_pointer(regs.r06) << bfendl;
475  bfdebug << "r07: " << view_as_pointer(regs.r07) << bfendl;
476  bfdebug << "r08: " << view_as_pointer(regs.r08) << bfendl;
477  bfdebug << "r09: " << view_as_pointer(regs.r09) << bfendl;
478  bfdebug << "r10: " << view_as_pointer(regs.r10) << bfendl;
479  bfdebug << "r11: " << view_as_pointer(regs.r11) << bfendl;
480  bfdebug << "r12: " << view_as_pointer(regs.r12) << bfendl;
481 }
482 
483 void
485 {
486  expects(regs.r05 != 0);
487  expects(regs.r08 != 0);
488  expects(regs.r06 != 0);
489  expects(regs.r09 != 0);
490  expects(regs.r09 >= regs.r06);
493 
494  auto &&imap = bfn::make_unique_map_x64<char>(regs.r05, vmcs::guest_cr3::get(), regs.r06, vmcs::guest_ia32_pat::get());
495  auto &&omap = bfn::make_unique_map_x64<char>(regs.r08, vmcs::guest_cr3::get(), regs.r09, vmcs::guest_ia32_pat::get());
496 
497  switch (regs.r04)
498  {
500  {
501  std::string ostr;
502  handle_vmcall_data_string_unformatted(std::string(imap.get(), regs.r06), ostr);
503  reply_with_string(regs, ostr, omap);
504  break;
505  }
506 
508  {
509  json ojson;
510  handle_vmcall_data_string_json(json::parse(std::string(imap.get(), regs.r06)), ojson);
511  reply_with_json(regs, ojson, omap);
512  break;
513  }
514 
516  {
519  regs.r09 = regs.r06;
520  break;
521  }
522 
523  default:
524  throw std::runtime_error("unknown vmcall data type");
525  }
526 }
527 
528 void
530 {
531  bfdebug << "vmcall event:" << bfendl;
532  bfdebug << "r02: " << view_as_pointer(regs.r02) << bfendl;
533 }
534 
535 void
537 { (void) regs; }
538 
539 void
541 { (void) regs; }
542 
543 void
545  const std::string &istr, std::string &ostr)
546 {
547  bfdebug << "received in vmm: " << istr << bfendl;
548  ostr = istr;
549 }
550 
551 void
553  const json &ijson, json &ojson)
554 {
555  bfdebug << "received in vmm: " << ijson << bfendl;
556  ojson = ijson;
557 }
558 
559 void
561  const bfn::unique_map_ptr_x64<char> &imap,
562  const bfn::unique_map_ptr_x64<char> &omap)
563 {
564  bfdebug << "received binary data" << bfendl;
565  __builtin_memcpy(omap.get(), imap.get(), imap.size());
566 }
567 
569  vmcall_registers_t &regs, const std::string &str,
570  const bfn::unique_map_ptr_x64<char> &omap)
571 {
572  auto &&len = str.length();
573 
574  __builtin_memcpy(omap.get(), str.data(), len);
575 
577  regs.r09 = len;
578 }
579 
580 void
582  vmcall_registers_t &regs, const json &str,
583  const bfn::unique_map_ptr_x64<char> &omap)
584 {
585  auto &&dmp = str.dump();
586  auto &&len = dmp.length();
587 
588  __builtin_memcpy(omap.get(), dmp.data(), len);
589 
591  regs.r09 = len;
592 }
expects(rbx)
virtual void handle_vmcall_data_binary_unformatted(const bfn::unique_map_ptr_x64< char > &imap, const bfn::unique_map_ptr_x64< char > &omap)
#define USER_VERSION_MAJOR
Definition: constants.h:53
#define BF_VMCALL_FAILURE
Definition: error_codes.h:135
#define VMCALL_VERSION
virtual size_type size() const noexcept
Definition: map_ptr_x64.h:714
void reply_with_string(vmcall_registers_t &regs, const std::string &str, const bfn::unique_map_ptr_x64< char > &omap)
std::mutex g_unimplemented_handler_mutex
#define VMCALL_IN_BUFFER_SIZE
Definition: constants.h:263
virtual void handle_exit(intel_x64::vmcs::value_type reason)
virtual void handle_vmcall_registers(vmcall_registers_t &regs)
void reply_with_json(vmcall_registers_t &regs, const json &str, const bfn::unique_map_ptr_x64< char > &omap)
#define USER_VERSION_PATCH
Definition: constants.h:61
virtual void handle_vmcall_start(vmcall_registers_t &regs)
virtual void promote()
virtual void resume()
#define VMCALL_OUT_BUFFER_SIZE
Definition: constants.h:272
#define BAREFLANK_VERSION_PATCH
Definition: constants.h:45
virtual void handle_vmcall_data(vmcall_registers_t &regs)
#define BAREFLANK_VERSION_MINOR
Definition: constants.h:44
virtual void handle_vmcall_event(vmcall_registers_t &regs)
void uint64_t uint64_t uint64_t *rdx noexcept
virtual void handle_vmcall_stop(vmcall_registers_t &regs)
#define USER_VERSION_MINOR
Definition: constants.h:57
virtual void handle_vmcall_data_string_json(const json &ijson, json &ojson)
auto get(A addr) noexcept
void set(A addr, T val) noexcept
virtual void complete_vmcall(ret_type ret, vmcall_registers_t &regs) noexcept
const void * view_as_pointer(const T val)
constexpr const auto addr
Definition: msrs_x64.h:50
constexpr const auto addr
virtual void halt() noexcept
virtual pointer get() const noexcept
Definition: map_ptr_x64.h:693
virtual void handle_vmcall_data_string_unformatted(const std::string &istr, std::string &ostr)
E guard_exceptions(E error_code, T func)
#define BAREFLANK_VERSION_MAJOR
Definition: constants.h:43
virtual void handle_vmcall_versions(vmcall_registers_t &regs)
void set(T val) noexcept
Definition: crs_intel_x64.h:52
state_save_intel_x64 * m_state_save
Definition: cache_x64.h:31
uint64_t value_type
#define VMCALL_MAGIC_NUMBER