command_line_parser.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 <exception.h>
26 #include <vmcall_interface.h>
27 #include <command_line_parser.h>
28 
29 // -----------------------------------------------------------------------------
30 // Implementation
31 // -----------------------------------------------------------------------------
32 
34 { reset(); }
35 
36 void
38 {
39  arg_type cmd;
40  arg_list_type filtered_args;
41 
42  auto ___ = gsl::on_failure([&]
43  { reset(); });
44 
45  for (auto arg = args.begin(); arg != args.end(); ++arg)
46  {
47  if (arg->empty() || arg->find_first_not_of(" \t") == std::string::npos)
48  continue;
49 
50  if (*arg == "--cpuid")
51  {
52  if (++arg == args.end())
53  break;
54 
55  m_cpuid = std::stoull(*arg, nullptr, 16);
56  continue;
57  }
58 
59  if (*arg == "--vcpuid")
60  {
61  if (++arg == args.end())
62  break;
63 
64  m_vcpuid = std::stoull(*arg, nullptr, 16);
65  continue;
66  }
67 
68  if (*arg == "-h" || *arg == "--help")
69  return reset();
70 
71  if (arg->front() == '-')
72  continue;
73 
74  if (cmd.empty())
75  {
76  cmd = *arg;
77  continue;
78  }
79 
80  filtered_args.push_back(*arg);
81  }
82 
83  if (cmd.empty())
84  return reset();
85 
86  if (cmd == "load") return parse_load(filtered_args);
87  if (cmd == "unload") return parse_unload(filtered_args);
88  if (cmd == "start") return parse_start(filtered_args);
89  if (cmd == "stop") return parse_stop(filtered_args);
90  if (cmd == "dump") return parse_dump(filtered_args);
91  if (cmd == "status") return parse_status(filtered_args);
92  if (cmd == "vmcall") return parse_vmcall(filtered_args);
93 
94  throw unknown_command(cmd);
95 }
96 
99 { return m_cmd; }
100 
103 { return m_modules; }
104 
107 { return m_cpuid; }
108 
111 { return m_vcpuid; }
112 
115 { return m_registers; }
116 
119 { return m_ifile; }
120 
123 { return m_ofile;}
124 
125 void
126 command_line_parser::reset() noexcept
127 {
128  m_cmd = command_type::help;
129  m_modules.clear();
130  m_cpuid = 0;
131  m_vcpuid = 0;
132  m_registers = registers_type{};
133  m_ifile.clear();
134  m_ofile.clear();
135  m_string_data.clear();
136 }
137 
138 void
139 command_line_parser::parse_load(arg_list_type &args)
140 {
141  if (args.empty())
142  throw missing_argument();
143 
144  m_cmd = command_type::load;
145  m_modules = args[0];
146 }
147 
148 void
149 command_line_parser::parse_unload(arg_list_type &args)
150 {
151  (void) args;
152  m_cmd = command_type::unload;
153 }
154 
155 void
156 command_line_parser::parse_start(arg_list_type &args)
157 {
158  (void) args;
159  m_cmd = command_type::start;
160 }
161 
162 void
163 command_line_parser::parse_stop(arg_list_type &args)
164 {
165  (void) args;
166  m_cmd = command_type::stop;
167 }
168 
169 void
170 command_line_parser::parse_dump(arg_list_type &args)
171 {
172  (void) args;
173  m_cmd = command_type::dump;
174 }
175 
176 void
177 command_line_parser::parse_status(arg_list_type &args)
178 {
179  (void) args;
180  m_cmd = command_type::status;
181 }
182 
183 void
184 command_line_parser::parse_vmcall(arg_list_type &args)
185 {
186  if (args.empty())
187  throw missing_argument();
188 
189  auto opcode = bfn::take(args, 0);
190 
191  if (opcode == "versions") return parse_vmcall_version(args);
192  if (opcode == "registers") return parse_vmcall_registers(args);
193  if (opcode == "string") return parse_vmcall_string(args);
194  if (opcode == "data") return parse_vmcall_data(args);
195  if (opcode == "event") return parse_vmcall_event(args);
196  if (opcode == "unittest") return parse_vmcall_unittest(args);
197 
198  throw unknown_vmcall_type(opcode);
199 }
200 
201 void
202 command_line_parser::parse_vmcall_version(arg_list_type &args)
203 {
204  if (args.empty())
205  throw missing_argument();
206 
207  m_registers.r00 = VMCALL_VERSIONS;
208  m_registers.r01 = VMCALL_MAGIC_NUMBER;
209  m_registers.r02 = std::stoull(args[0]);
210 
211  m_cmd = command_type::vmcall;
212 }
213 
214 void
215 command_line_parser::parse_vmcall_registers(arg_list_type &args)
216 {
217  auto index = args.size() - 1;
218 
219  m_registers.r00 = VMCALL_REGISTERS;
220  m_registers.r01 = VMCALL_MAGIC_NUMBER;
221 
222  switch (index)
223  {
224  case 0xD:
225  m_registers.r15 = std::stoull(args[index--], nullptr, 16);
226  case 0xC:
227  m_registers.r14 = std::stoull(args[index--], nullptr, 16);
228  case 0xB:
229  m_registers.r13 = std::stoull(args[index--], nullptr, 16);
230  case 0xA:
231  m_registers.r12 = std::stoull(args[index--], nullptr, 16);
232  case 0x9:
233  m_registers.r11 = std::stoull(args[index--], nullptr, 16);
234  case 0x8:
235  m_registers.r10 = std::stoull(args[index--], nullptr, 16);
236  case 0x7:
237  m_registers.r09 = std::stoull(args[index--], nullptr, 16);
238  case 0x6:
239  m_registers.r08 = std::stoull(args[index--], nullptr, 16);
240  case 0x5:
241  m_registers.r07 = std::stoull(args[index--], nullptr, 16);
242  case 0x4:
243  m_registers.r06 = std::stoull(args[index--], nullptr, 16);
244  case 0x3:
245  m_registers.r05 = std::stoull(args[index--], nullptr, 16);
246  case 0x2:
247  m_registers.r04 = std::stoull(args[index--], nullptr, 16);
248  case 0x1:
249  m_registers.r03 = std::stoull(args[index--], nullptr, 16);
250  case 0x0:
251  m_registers.r02 = std::stoull(args[index--], nullptr, 16);
252  break;
253 
254  default:
255  break;
256  }
257 
258  m_cmd = command_type::vmcall;
259 }
260 
261 void
262 command_line_parser::parse_vmcall_string(arg_list_type &args)
263 {
264  if (args.empty())
265  throw missing_argument();
266 
267  auto type = bfn::take(args, 0);
268 
269  if (type == "unformatted") return parse_vmcall_string_unformatted(args);
270  if (type == "json") return parse_vmcall_string_json(args);
271 
273 }
274 
275 void
276 command_line_parser::parse_vmcall_data(arg_list_type &args)
277 {
278  if (args.empty())
279  throw missing_argument();
280 
281  auto type = bfn::take(args, 0);
282  if (type == "unformatted") return parse_vmcall_data_unformatted(args);
283 
285 }
286 
287 void
288 command_line_parser::parse_vmcall_event(arg_list_type &args)
289 {
290  if (args.empty())
291  throw missing_argument();
292 
293  m_registers.r00 = VMCALL_EVENT;
294  m_registers.r01 = VMCALL_MAGIC_NUMBER;
295  m_registers.r02 = std::stoull(args[0], nullptr, 16);
296 
297  m_cmd = command_type::vmcall;
298 }
299 
300 void
301 command_line_parser::parse_vmcall_unittest(arg_list_type &args)
302 {
303  if (args.empty())
304  throw missing_argument();
305 
306  m_registers.r00 = VMCALL_UNITTEST;
307  m_registers.r01 = VMCALL_MAGIC_NUMBER;
308  m_registers.r02 = std::stoull(args[0], nullptr, 16);
309 
310  m_cmd = command_type::vmcall;
311 }
312 
313 void
314 command_line_parser::parse_vmcall_string_unformatted(arg_list_type &args)
315 {
316  if (args.empty())
317  throw missing_argument();
318 
319  m_string_data = args[0];
320 
321  m_registers.r00 = VMCALL_DATA;
322  m_registers.r01 = VMCALL_MAGIC_NUMBER;
323  m_registers.r02 = 0;
324  m_registers.r03 = 0;
325  m_registers.r04 = VMCALL_DATA_STRING_UNFORMATTED;
326  m_registers.r05 = reinterpret_cast<decltype(m_registers.r05)>(m_string_data.data());
327  m_registers.r06 = m_string_data.length();
328 
329  m_cmd = command_type::vmcall;
330 }
331 
332 void
333 command_line_parser::parse_vmcall_string_json(arg_list_type &args)
334 {
335  if (args.empty())
336  throw missing_argument();
337 
338  m_string_data = json::parse(args[0]).dump();
339 
340  m_registers.r00 = VMCALL_DATA;
341  m_registers.r01 = VMCALL_MAGIC_NUMBER;
342  m_registers.r02 = 0;
343  m_registers.r03 = 0;
344  m_registers.r04 = VMCALL_DATA_STRING_JSON;
345  m_registers.r05 = reinterpret_cast<decltype(m_registers.r05)>(m_string_data.data());
346  m_registers.r06 = m_string_data.length();
347 
348  m_cmd = command_type::vmcall;
349 }
350 
351 void
352 command_line_parser::parse_vmcall_data_unformatted(arg_list_type &args)
353 {
354  if (args.size() < 2)
355  throw missing_argument();
356 
357  m_registers.r00 = VMCALL_DATA;
358  m_registers.r01 = VMCALL_MAGIC_NUMBER;
359  m_registers.r02 = 0;
360  m_registers.r03 = 0;
361  m_registers.r04 = VMCALL_DATA_BINARY_UNFORMATTED;
362 
363  m_ifile = args[0];
364  m_ofile = args[1];
365 
366  m_cmd = command_type::vmcall;
367 }
ioctl::registers_type registers_type
#define missing_argument()
Definition: exception.h:203
#define unknown_vmcall_type(a)
Definition: exception.h:150
virtual const filename_type & ifile() const noexcept
file::filename_type filename_type
virtual void parse(const arg_list_type &args)
virtual cpuid_type cpuid() const noexcept
void help()
Definition: main.cpp:70
ioctl::cpuid_type cpuid_type
void uint64_t uint64_t uint64_t *rdx noexcept
auto index(const T virt, const F from)
#define unknown_vmcall_string_type(a)
Definition: exception.h:170
virtual command_type cmd() const noexcept
std::vector< arg_type > arg_list_type
#define unknown_vmcall_data_type(a)
Definition: exception.h:190
virtual const filename_type & ofile() const noexcept
virtual const registers_type & registers() const noexcept
ioctl::vcpuid_type vcpuid_type
virtual vcpuid_type vcpuid() const noexcept
virtual const filename_type & modules() const noexcept
#define unknown_command(a)
Definition: exception.h:130
#define VMCALL_MAGIC_NUMBER