Package modules :: Package machinery :: Module virtualbox
[hide private]
[frames] | no frames]

Source Code for Module modules.machinery.virtualbox

  1  # Copyright (C) 2010-2015 Cuckoo Foundation. 
  2  # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org 
  3  # See the file 'docs/LICENSE' for copying permission. 
  4   
  5  import os 
  6  import re 
  7  import time 
  8  import logging 
  9  import subprocess 
 10  import os.path 
 11   
 12  from lib.cuckoo.common.abstracts import Machinery 
 13  from lib.cuckoo.common.exceptions import CuckooCriticalError 
 14  from lib.cuckoo.common.exceptions import CuckooMachineError 
 15   
 16  log = logging.getLogger(__name__) 
 17   
18 -class VirtualBox(Machinery):
19 """Virtualization layer for VirtualBox.""" 20 21 # VM states. 22 SAVED = "saved" 23 RUNNING = "running" 24 POWEROFF = "poweroff" 25 ABORTED = "aborted" 26 ERROR = "machete" 27
28 - def _initialize_check(self):
29 """Runs all checks when a machine manager is initialized. 30 @raise CuckooMachineError: if VBoxManage is not found. 31 """ 32 # VirtualBox specific checks. 33 if not self.options.virtualbox.path: 34 raise CuckooCriticalError("VirtualBox VBoxManage path missing, " 35 "please add it to the config file") 36 if not os.path.exists(self.options.virtualbox.path): 37 raise CuckooCriticalError("VirtualBox VBoxManage not found at " 38 "specified path \"%s\"" % 39 self.options.virtualbox.path) 40 41 # Base checks. 42 super(VirtualBox, self)._initialize_check()
43
44 - def start(self, label):
45 """Start a virtual machine. 46 @param label: virtual machine name. 47 @raise CuckooMachineError: if unable to start. 48 """ 49 log.debug("Starting vm %s" % label) 50 51 if self._status(label) == self.RUNNING: 52 raise CuckooMachineError("Trying to start an already " 53 "started vm %s" % label) 54 55 vm_info = self.db.view_machine_by_label(label) 56 virtualbox_args = [self.options.virtualbox.path, "snapshot", label] 57 if vm_info.snapshot: 58 log.debug("Using snapshot {0} for virtual machine " 59 "{1}".format(vm_info.snapshot, label)) 60 virtualbox_args.extend(["restore", vm_info.snapshot]) 61 else: 62 log.debug("Using current snapshot for virtual machine " 63 "{0}".format(label)) 64 virtualbox_args.extend(["restorecurrent"]) 65 66 try: 67 if subprocess.call(virtualbox_args, 68 stdout=subprocess.PIPE, 69 stderr=subprocess.PIPE): 70 raise CuckooMachineError("VBoxManage exited with error " 71 "restoring the machine's snapshot") 72 except OSError as e: 73 raise CuckooMachineError("VBoxManage failed restoring the " 74 "machine: %s" % e) 75 76 self._wait_status(label, self.SAVED) 77 78 try: 79 proc = subprocess.Popen([self.options.virtualbox.path, 80 "startvm", 81 label, 82 "--type", 83 self.options.virtualbox.mode], 84 stdout=subprocess.PIPE, 85 stderr=subprocess.PIPE) 86 output, err = proc.communicate() 87 if err: 88 raise OSError(err) 89 except OSError as e: 90 raise CuckooMachineError("VBoxManage failed starting the machine " 91 "in %s mode: %s" % 92 (self.options.virtualbox.mode.upper(), e)) 93 self._wait_status(label, self.RUNNING)
94
95 - def stop(self, label):
96 """Stops a virtual machine. 97 @param label: virtual machine name. 98 @raise CuckooMachineError: if unable to stop. 99 """ 100 log.debug("Stopping vm %s" % label) 101 102 if self._status(label) in [self.POWEROFF, self.ABORTED]: 103 raise CuckooMachineError("Trying to stop an already stopped " 104 "vm %s" % label) 105 106 try: 107 proc = subprocess.Popen([self.options.virtualbox.path, 108 "controlvm", label, "poweroff"], 109 stdout=subprocess.PIPE, 110 stderr=subprocess.PIPE) 111 # Sometimes VBoxManage stucks when stopping vm so we needed 112 # to add a timeout and kill it after that. 113 stop_me = 0 114 while proc.poll() is None: 115 if stop_me < int(self.options_globals.timeouts.vm_state): 116 time.sleep(1) 117 stop_me += 1 118 else: 119 log.debug("Stopping vm %s timeouted. Killing" % label) 120 proc.terminate() 121 122 if proc.returncode != 0 and \ 123 stop_me < int(self.options_globals.timeouts.vm_state): 124 log.debug("VBoxManage exited with error " 125 "powering off the machine") 126 except OSError as e: 127 raise CuckooMachineError("VBoxManage failed powering off the " 128 "machine: %s" % e) 129 self._wait_status(label, [self.POWEROFF, self.ABORTED, self.SAVED])
130
131 - def _list(self):
132 """Lists virtual machines installed. 133 @return: virtual machine names list. 134 """ 135 try: 136 proc = subprocess.Popen([self.options.virtualbox.path, 137 "list", "vms"], 138 stdout=subprocess.PIPE, 139 stderr=subprocess.PIPE) 140 output, _ = proc.communicate() 141 except OSError as e: 142 raise CuckooMachineError("VBoxManage error listing " 143 "installed machines: %s" % e) 144 145 machines = [] 146 for line in output.split("\n"): 147 try: 148 label = line.split('"')[1] 149 if label == "<inaccessible>": 150 log.warning("Found an inaccessible virtual machine, " 151 "please check its state.") 152 else: 153 machines.append(label) 154 except IndexError: 155 continue 156 157 return machines
158
159 - def _status(self, label):
160 """Gets current status of a vm. 161 @param label: virtual machine name. 162 @return: status string. 163 """ 164 log.debug("Getting status for %s" % label) 165 status = None 166 try: 167 proc = subprocess.Popen([self.options.virtualbox.path, 168 "showvminfo", 169 label, 170 "--machinereadable"], 171 stdout=subprocess.PIPE, 172 stderr=subprocess.PIPE) 173 output, err = proc.communicate() 174 175 if proc.returncode != 0: 176 # It's quite common for virtualbox crap utility to exit with: 177 # VBoxManage: error: Details: code E_ACCESSDENIED (0x80070005) 178 # So we just log to debug this. 179 log.debug("VBoxManage returns error checking status for " 180 "machine %s: %s", label, err) 181 status = self.ERROR 182 except OSError as e: 183 log.warning("VBoxManage failed to check status for machine %s: %s", 184 label, e) 185 status = self.ERROR 186 if not status: 187 for line in output.split("\n"): 188 state = re.match(r"VMState=\"(\w+)\"", line, re.M|re.I) 189 if state: 190 status = state.group(1) 191 log.debug("Machine %s status %s" % (label, status)) 192 status = status.lower() 193 # Report back status. 194 if status: 195 self.set_status(label, status) 196 return status 197 else: 198 raise CuckooMachineError("Unable to get status for %s" % label)
199
200 - def dump_memory(self, label, path):
201 """Takes a memory dump. 202 @param path: path to where to store the memory dump. 203 """ 204 try: 205 subprocess.call([self.options.virtualbox.path, "debugvm", 206 label, "dumpguestcore", "--filename", path], 207 stdout=subprocess.PIPE, 208 stderr=subprocess.PIPE) 209 log.info("Successfully generated memory dump for virtual machine " 210 "with label %s to path %s", label, path) 211 except OSError as e: 212 raise CuckooMachineError("VBoxManage failed to take a memory " 213 "dump of the machine with label %s: %s" % 214 (label, e))
215