ioctl_driver.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 <json.h>
25 #include <debug.h>
26 #include <exception.h>
27 #include <ioctl_driver.h>
28 #include <vmcall_interface.h>
29 #include <driver_entry_interface.h>
30 
31 ioctl_driver::ioctl_driver(gsl::not_null<file *> f,
32  gsl::not_null<ioctl *> ctl,
33  gsl::not_null<command_line_parser *> clp) :
34  m_file(f),
35  m_ioctl(ctl),
36  m_clp(clp)
37 { }
38 
39 void
41 {
42  switch (m_clp->cmd())
43  {
45  return;
46 
48  return this->load_vmm();
49 
51  return this->unload_vmm();
52 
54  return this->start_vmm();
55 
57  return this->stop_vmm();
58 
60  return this->dump_vmm();
61 
63  return this->vmm_status();
64 
66  return this->vmcall();
67  }
68 }
69 
70 #include <random>
71 #include <algorithm>
72 
73 void
74 ioctl_driver::load_vmm()
75 {
76  switch (get_status())
77  {
78  case VMM_RUNNING: stop_vmm();
79  case VMM_LOADED: unload_vmm();
80  case VMM_UNLOADED: break;
81  case VMM_CORRUPT: throw corrupt_vmm();
82  default: throw unknown_status();
83  }
84 
85  auto &&modules = json::parse(m_file->read_text(m_clp->modules()));
86 
87  auto ___ = gsl::on_failure([&]
88  { unload_vmm(); });
89 
90  auto &&module_list = modules["modules"];
91 
92  std::random_device rd;
93  std::mt19937 g(rd());
94 
95  std::shuffle(module_list.begin(), module_list.end(), g);
96 
97  for (const auto &module : module_list)
98  m_ioctl->call_ioctl_add_module(m_file->read_binary(module));
99 
100  m_ioctl->call_ioctl_load_vmm();
101 }
102 
103 void
104 ioctl_driver::unload_vmm()
105 {
106  switch (get_status())
107  {
108  case VMM_RUNNING: stop_vmm();
109  case VMM_LOADED: break;
110  case VMM_UNLOADED: break;
111  case VMM_CORRUPT: throw corrupt_vmm();
112  default: throw unknown_status();
113  }
114 
115  m_ioctl->call_ioctl_unload_vmm();
116 }
117 
118 void
119 ioctl_driver::start_vmm()
120 {
121  switch (get_status())
122  {
123  case VMM_RUNNING: stop_vmm();
124  case VMM_LOADED: break;
125  case VMM_UNLOADED: throw invalid_vmm_state("vmm must be loaded first");
126  case VMM_CORRUPT: throw corrupt_vmm();
127  default: throw unknown_status();
128  }
129 
130  m_ioctl->call_ioctl_start_vmm();
131 }
132 
133 void
134 ioctl_driver::stop_vmm()
135 {
136  switch (get_status())
137  {
138  case VMM_RUNNING: break;
139  case VMM_LOADED: return;
140  case VMM_UNLOADED: return;
141  case VMM_CORRUPT: throw corrupt_vmm();
142  default: throw unknown_status();
143  }
144 
145  m_ioctl->call_ioctl_stop_vmm();
146 }
147 
148 void
149 ioctl_driver::dump_vmm()
150 {
151  auto drr = ioctl::drr_type{};
152  auto buffer = std::make_unique<char[]>(DEBUG_RING_SIZE);
153 
154  switch (get_status())
155  {
156  case VMM_RUNNING: break;
157  case VMM_LOADED: break;
158  case VMM_UNLOADED: throw invalid_vmm_state("vmm must be loaded first");
159  case VMM_CORRUPT: throw corrupt_vmm();
160  default: throw unknown_status();
161  }
162 
163  m_ioctl->call_ioctl_dump_vmm(&drr, m_clp->vcpuid());
164 
165  if (debug_ring_read(&drr, buffer.get(), DEBUG_RING_SIZE) > 0)
166  std::cout << buffer.get();
167 }
168 
169 void
170 ioctl_driver::vmm_status()
171 {
172  switch (get_status())
173  {
174  case VMM_UNLOADED: std::cout << "VMM_UNLOADED\n"; return;
175  case VMM_LOADED: std::cout << "VMM_LOADED\n"; return;
176  case VMM_RUNNING: std::cout << "VMM_RUNNING\n"; return;
177  case VMM_CORRUPT: std::cout << "VMM_CORRUPT\n"; return;
178  default: throw unknown_status();
179  }
180 }
181 
182 void
183 ioctl_driver::vmcall()
184 {
185  auto regs = m_clp->registers();
186 
187  switch (get_status())
188  {
189  case VMM_RUNNING: break;
190  case VMM_LOADED: throw invalid_vmm_state("vmm must be running first");
191  case VMM_UNLOADED: throw invalid_vmm_state("vmm must be running first");
192  case VMM_CORRUPT: throw corrupt_vmm();
193  default: throw unknown_status();
194  }
195 
196  switch (regs.r00)
197  {
198  case VMCALL_VERSIONS:
199  this->vmcall_versions(regs);
200  break;
201 
202  case VMCALL_REGISTERS:
203  this->vmcall_registers(regs);
204  break;
205 
206  case VMCALL_DATA:
207  this->vmcall_data(regs);
208  break;
209 
210  case VMCALL_EVENT:
211  this->vmcall_event(regs);
212  break;
213 
214  case VMCALL_UNITTEST:
215  this->vmcall_unittest(regs);
216  break;
217 
218  default:
219  throw std::logic_error("unknown vmcall opcode");
220  }
221 }
222 
223 void
224 ioctl_driver::vmcall_send_regs(registers_type &regs)
225 {
226  m_ioctl->call_ioctl_vmcall(&regs, m_clp->cpuid());
227 
228  if (regs.r01 != 0)
229  throw ioctl_failed(IOCTL_VMCALL);
230 }
231 
232 void
233 ioctl_driver::vmcall_versions(registers_type &regs)
234 {
235  this->vmcall_send_regs(regs);
236 
237  switch (regs.r02)
238  {
240  std::cout << "VMCALL_VERSIONS: " << view_as_pointer(regs.r03) << std::endl;
241  break;
242 
244  std::cout << "BAREFLANK_VERSION_MAJOR: " << view_as_pointer(regs.r03) << std::endl;
245  std::cout << "BAREFLANK_VERSION_MINOR: " << view_as_pointer(regs.r04) << std::endl;
246  std::cout << "BAREFLANK_VERSION_PATCH: " << view_as_pointer(regs.r05) << std::endl;
247  break;
248 
249  case VMCALL_VERSION_USER:
250  std::cout << "USER_VERSION_MAJOR: " << view_as_pointer(regs.r03) << std::endl;
251  std::cout << "USER_VERSION_MINOR: " << view_as_pointer(regs.r04) << std::endl;
252  std::cout << "USER_VERSION_PATCH: " << view_as_pointer(regs.r05) << std::endl;
253  break;
254 
255  default:
256  break;
257  }
258 }
259 
260 void
261 ioctl_driver::vmcall_registers(registers_type &regs)
262 {
263  this->vmcall_send_regs(regs);
264 
265  std::cout << "r02: " << view_as_pointer(regs.r02) << std::endl;
266  std::cout << "r03: " << view_as_pointer(regs.r03) << std::endl;
267  std::cout << "r04: " << view_as_pointer(regs.r04) << std::endl;
268  std::cout << "r05: " << view_as_pointer(regs.r05) << std::endl;
269  std::cout << "r06: " << view_as_pointer(regs.r06) << std::endl;
270  std::cout << "r07: " << view_as_pointer(regs.r07) << std::endl;
271  std::cout << "r08: " << view_as_pointer(regs.r08) << std::endl;
272  std::cout << "r09: " << view_as_pointer(regs.r09) << std::endl;
273  std::cout << "r10: " << view_as_pointer(regs.r10) << std::endl;
274  std::cout << "r11: " << view_as_pointer(regs.r11) << std::endl;
275  std::cout << "r12: " << view_as_pointer(regs.r12) << std::endl;
276  // std::cout << "r13: " << view_as_pointer(regs.r13) << std::endl;
277  // std::cout << "r14: " << view_as_pointer(regs.r14) << std::endl;
278  // std::cout << "r15: " << view_as_pointer(regs.r15) << std::endl;
279 }
280 
281 void
282 ioctl_driver::vmcall_data(registers_type &regs)
283 {
284  switch (regs.r04)
285  {
288  this->vmcall_data_string(regs);
289  break;
290 
292  this->vmcall_data_binary(regs);
293  break;
294 
295  default:
296  throw std::logic_error("unknown vmcall data type");
297  break;
298  }
299 }
300 
301 void
302 ioctl_driver::vmcall_data_string(registers_type &regs)
303 {
304  auto &&obuffer = std::make_unique<char[]>(VMCALL_OUT_BUFFER_SIZE);
305  regs.r08 = reinterpret_cast<decltype(regs.r08)>(obuffer.get());
306  regs.r09 = VMCALL_OUT_BUFFER_SIZE;
307 
308  vmcall_send_regs(regs);
309 
310  switch (regs.r07)
311  {
313 
314  if (regs.r09 >= VMCALL_OUT_BUFFER_SIZE)
315  throw std::out_of_range("return output buffer size out of range");
316 
317  std::cout << "received from vmm: \n" << json::parse(std::string(obuffer.get(), regs.r09)).dump(4) << '\n';
318  break;
319 
321 
322  if (regs.r09 >= VMCALL_OUT_BUFFER_SIZE)
323  throw std::out_of_range("return output buffer size out of range");
324 
325  std::cout << "received from vmm: " << std::string(obuffer.get(), regs.r09) << '\n';
326  break;
327 
328  default:
329  break;
330  }
331 }
332 
333 void
334 ioctl_driver::vmcall_data_binary(registers_type &regs)
335 {
336  auto &&ifile_buffer = m_file->read_binary(m_clp->ifile());
337  auto &&ofile_buffer = file::binary_data(VMCALL_OUT_BUFFER_SIZE);
338  regs.r05 = reinterpret_cast<decltype(regs.r05)>(ifile_buffer.data());
339  regs.r06 = ifile_buffer.size();
340  regs.r08 = reinterpret_cast<decltype(regs.r08)>(ofile_buffer.data());
341  regs.r09 = VMCALL_OUT_BUFFER_SIZE;
342 
343  vmcall_send_regs(regs);
344 
345  switch (regs.r07)
346  {
348 
349  if (regs.r09 >= VMCALL_OUT_BUFFER_SIZE)
350  throw std::out_of_range("return output buffer size out of range");
351 
352  ofile_buffer.resize(regs.r09);
353  m_file->write_binary(m_clp->ofile(), ofile_buffer);
354  break;
355 
356  default:
357  break;
358  }
359 }
360 
361 void
362 ioctl_driver::vmcall_event(registers_type &regs)
363 {
364  vmcall_send_regs(regs);
365  std::cout << "success" << std::endl;
366 }
367 
368 void
369 ioctl_driver::vmcall_unittest(registers_type &regs)
370 {
371  vmcall_send_regs(regs);
372  std::cout << "\033[1;36m" << std::hex << "0x" << regs.r02 << std::dec << ":\033[1;32m passed\033[0m\n";
373 }
374 
376 ioctl_driver::get_status() const
377 {
378  status_type status = -1;
379  m_ioctl->call_ioctl_vmm_status(&status);
380 
381  return status;
382 }
#define invalid_vmm_state(a)
Definition: exception.h:308
#define VMM_LOADED
ioctl::status_type status_type
Definition: ioctl_driver.h:43
#define unknown_status()
Definition: exception.h:288
#define VMCALL_OUT_BUFFER_SIZE
Definition: constants.h:272
uint64_t debug_ring_read(struct debug_ring_resources_t *drr, char *str, uint64_t len)
void help()
Definition: main.cpp:70
debug_ring_resources_t * drr
ioctl_driver(gsl::not_null< file *> f, gsl::not_null< ioctl *> ctl, gsl::not_null< command_line_parser *> clp)
#define ioctl_failed(a)
Definition: exception.h:262
#define VMM_UNLOADED
const void * view_as_pointer(const T val)
#define DEBUG_RING_SIZE
Definition: constants.h:206
#define VMM_RUNNING
#define VMM_CORRUPT
vmcall_versions
#define corrupt_vmm()
Definition: exception.h:275
std::vector< char > binary_data
Definition: file.h:40