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

Source Code for Module modules.machinery.virtualbox

  1  # Copyright (C) 2010-2014 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 subprocess.call([self.options.virtualbox.path, 80 "startvm", 81 label, 82 "--type", 83 self.options.virtualbox.mode], 84 stdout=subprocess.PIPE, 85 stderr=subprocess.PIPE) 86 except OSError as e: 87 raise CuckooMachineError("VBoxManage failed starting the machine " 88 "in %s mode: %s" % 89 (self.options.virtualbox.mode.upper(), e)) 90 self._wait_status(label, self.RUNNING)
91
92 - def stop(self, label):
93 """Stops a virtual machine. 94 @param label: virtual machine name. 95 @raise CuckooMachineError: if unable to stop. 96 """ 97 log.debug("Stopping vm %s" % label) 98 99 if self._status(label) in [self.POWEROFF, self.ABORTED]: 100 raise CuckooMachineError("Trying to stop an already stopped " 101 "vm %s" % label) 102 103 try: 104 proc = subprocess.Popen([self.options.virtualbox.path, 105 "controlvm", label, "poweroff"], 106 stdout=subprocess.PIPE, 107 stderr=subprocess.PIPE) 108 # Sometimes VBoxManage stucks when stopping vm so we needed 109 # to add a timeout and kill it after that. 110 stop_me = 0 111 while proc.poll() is None: 112 if stop_me < int(self.options_globals.timeouts.vm_state): 113 time.sleep(1) 114 stop_me += 1 115 else: 116 log.debug("Stopping vm %s timeouted. Killing" % label) 117 proc.terminate() 118 119 if proc.returncode != 0 and \ 120 stop_me < int(self.options_globals.timeouts.vm_state): 121 log.debug("VBoxManage exited with error " 122 "powering off the machine") 123 except OSError as e: 124 raise CuckooMachineError("VBoxManage failed powering off the " 125 "machine: %s" % e) 126 self._wait_status(label, [self.POWEROFF, self.ABORTED, self.SAVED])
127
128 - def _list(self):
129 """Lists virtual machines installed. 130 @return: virtual machine names list. 131 """ 132 try: 133 proc = subprocess.Popen([self.options.virtualbox.path, 134 "list", "vms"], 135 stdout=subprocess.PIPE, 136 stderr=subprocess.PIPE) 137 output, _ = proc.communicate() 138 except OSError as e: 139 raise CuckooMachineError("VBoxManage error listing " 140 "installed machines: %s" % e) 141 142 machines = [] 143 for line in output.split("\n"): 144 try: 145 label = line.split('"')[1] 146 if label == "<inaccessible>": 147 log.warning("Found an inaccessible virtual machine: " 148 "please check his state") 149 else: 150 machines.append(label) 151 except IndexError: 152 continue 153 154 return machines
155
156 - def _status(self, label):
157 """Gets current status of a vm. 158 @param label: virtual machine name. 159 @return: status string. 160 """ 161 log.debug("Getting status for %s" % label) 162 status = None 163 try: 164 proc = subprocess.Popen([self.options.virtualbox.path, 165 "showvminfo", 166 label, 167 "--machinereadable"], 168 stdout=subprocess.PIPE, 169 stderr=subprocess.PIPE) 170 output, err = proc.communicate() 171 172 if proc.returncode != 0: 173 # It's quite common for virtualbox crap utility to exit with: 174 # VBoxManage: error: Details: code E_ACCESSDENIED (0x80070005) 175 # So we just log to debug this. 176 log.debug("VBoxManage returns error checking status for " 177 "machine %s: %s", label, err) 178 status = self.ERROR 179 except OSError as e: 180 log.warning("VBoxManage failed to check status for machine %s: %s", 181 label, e) 182 status = self.ERROR 183 if not status: 184 for line in output.split("\n"): 185 state = re.match(r"VMState=\"(\w+)\"", line, re.M|re.I) 186 if state: 187 status = state.group(1) 188 log.debug("Machine %s status %s" % (label, status)) 189 status = status.lower() 190 # Report back status. 191 if status: 192 self.set_status(label, status) 193 return status 194 else: 195 raise CuckooMachineError("Unable to get status for %s" % label)
196
197 - def dump_memory(self, label, path):
198 """Takes a memory dump. 199 @param path: path to where to store the memory dump. 200 """ 201 try: 202 subprocess.call([self.options.virtualbox.path, "debugvm", 203 label, "dumpguestcore", "--filename", path], 204 stdout=subprocess.PIPE, 205 stderr=subprocess.PIPE) 206 log.info("Successfully generated memory dump for virtual machine " 207 "with label %s to path %s", label, path) 208 except OSError as e: 209 raise CuckooMachineError("VBoxManage failed to take a memory " 210 "dump of the machine with label %s: %s" % 211 (label, e))
212