1
2
3
4
5
6 import os
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
19
20
21
22
23 QEMU_ARGS = {
24 "default": {
25 "cmdline": ["qemu-system-x86_64", "-display", "none"],
26 "params": {
27 "memory": "512M",
28 "mac": "52:54:00:12:34:56",
29 "kernel": "{imagepath}/vmlinuz",
30 },
31 },
32 "mipsel": {
33 "cmdline": [
34 "qemu-system-mipsel", "-display", "none", "-M", "malta", "-m", "{memory}",
35 "-kernel", "{kernel}",
36 "-hda", "{snapshot_path}",
37 "-append", "root=/dev/sda1 console=tty0",
38 "-netdev", "tap,id=net_{vmname},ifname=tap_{vmname}",
39 "-device", "e1000,netdev=net_{vmname},mac={mac}",
40 ],
41 "params": {
42 "kernel": "{imagepath}/vmlinux-3.2.0-4-4kc-malta-mipsel",
43 }
44 },
45 "mips": {
46 "cmdline": [
47 "qemu-system-mips", "-display", "none", "-M", "malta", "-m", "{memory}",
48 "-kernel", "{kernel}",
49 "-hda", "{snapshot_path}",
50 "-append", "root=/dev/sda1 console=tty0",
51 "-netdev", "tap,id=net_{vmname},ifname=tap_{vmname}",
52 "-device", "e1000,netdev=net_{vmname},mac={mac}",
53 ],
54 "params": {
55 "kernel": "{imagepath}/vmlinux-3.2.0-4-4kc-malta-mips",
56 }
57 },
58 "armwrt": {
59 "cmdline": [
60 "qemu-system-arm", "-display", "none", "-M", "realview-eb-mpcore", "-m", "{memory}",
61 "-kernel", "{kernel}",
62 "-drive", "if=sd,cache=unsafe,file={snapshot_path}",
63 "-append", "console=ttyAMA0 root=/dev/mmcblk0 rootwait",
64 "-net", "tap,ifname=tap_{vmname}", "-net", "nic,macaddr={mac}",
65 ],
66 "params": {
67 "kernel": "{imagepath}/openwrt-realview-vmlinux.elf",
68 }
69 },
70 "arm": {
71 "cmdline": [
72 "qemu-system-arm", "-display", "none", "-M", "versatilepb", "-m", "{memory}",
73 "-kernel", "{kernel}", "-initrd", "{initrd}",
74 "-hda", "{snapshot_path}",
75 "-append", "root=/dev/sda1",
76 "-net", "tap,ifname=tap_{vmname}", "-net", "nic,macaddr={mac}",
77 ],
78 "params": {
79 "memory": "256M",
80 "kernel": "{imagepath}/vmlinuz-3.2.0-4-versatile-arm",
81 "initrd": "{imagepath}/initrd-3.2.0-4-versatile-arm",
82 }
83 },
84 "x64": {
85 "cmdline": [
86 "qemu-system-x86_64", "-display", "none", "-m", "{memory}",
87 "-hda", "{snapshot_path}",
88 "-net", "tap,ifname=tap_{vmname}", "-net", "nic,macaddr={mac}",
89 ],
90 "params": {
91 "memory": "1024M",
92 }
93 },
94 "x86": {
95 "cmdline": [
96 "qemu-system-i386", "-display", "none", "-m", "{memory}",
97 "-hda", "{snapshot_path}",
98 "-net", "tap,ifname=tap_{vmname}", "-net", "nic,macaddr={mac}",
99 ],
100 "params": {
101 "memory": "1024M",
102 }
103 },
104 }
105
106 -class QEMU(Machinery):
107 """Virtualization layer for QEMU (non-KVM)."""
108
109
110 RUNNING = "running"
111 STOPPED = "stopped"
112 ERROR = "machete"
113
117
119 """Runs all checks when a machine manager is initialized.
120 @raise CuckooMachineError: if QEMU binary is not found.
121 """
122
123 if not self.options.qemu.path:
124 raise CuckooCriticalError("QEMU binary path missing, "
125 "please add it to the config file")
126 if not os.path.exists(self.options.qemu.path):
127 raise CuckooCriticalError("QEMU binary not found at "
128 "specified path \"%s\"" %
129 self.options.qemu.path)
130
131 self.qemu_dir = os.path.dirname(self.options.qemu.path)
132 self.qemu_img = os.path.join(self.qemu_dir, "qemu-img")
133
134 - def start(self, label, task):
135 """Start a virtual machine.
136 @param label: virtual machine label.
137 @param task: task object.
138 @raise CuckooMachineError: if unable to start.
139 """
140 log.debug("Starting vm %s" % label)
141
142 vm_info = self.db.view_machine_by_label(label)
143 vm_options = getattr(self.options, vm_info.name)
144
145 snapshot_path = os.path.join(os.path.dirname(vm_options.image), vm_info.name) + ".qcow2"
146 if os.path.exists(snapshot_path):
147 os.remove(snapshot_path)
148
149
150 try:
151 proc = subprocess.Popen([self.qemu_img, "create", "-f", "qcow2", "-b", vm_options.image, snapshot_path],
152 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
153 output, err = proc.communicate()
154 if err:
155 raise OSError(err)
156 except OSError as e:
157 raise CuckooMachineError("QEMU failed starting the machine: %s" % e)
158
159 vm_arch = getattr(vm_options, "arch", "default")
160 arch_config = dict(QEMU_ARGS[vm_arch])
161 cmdline = arch_config["cmdline"]
162 params = dict(QEMU_ARGS["default"]["params"])
163 params.update(QEMU_ARGS[vm_arch]["params"])
164
165 params.update({
166 "imagepath": os.path.dirname(vm_options.image),
167 "snapshot_path": snapshot_path,
168 "vmname": vm_info.name,
169 })
170
171
172
173 for var in ["mac", "kernel", "initrd"]:
174 val = getattr(vm_options, var, params.get(var, None))
175 if not val:
176 continue
177 params[var] = val.format(**params)
178
179
180 final_cmdline = [i.format(**params) for i in cmdline]
181
182 log.debug("Executing QEMU %r", final_cmdline)
183
184 try:
185 proc = subprocess.Popen(final_cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
186 self.state[vm_info.name] = proc
187 except OSError as e:
188 raise CuckooMachineError("QEMU failed starting the machine: %s" % e)
189
190 - def stop(self, label):
191 """Stops a virtual machine.
192 @param label: virtual machine label.
193 @raise CuckooMachineError: if unable to stop.
194 """
195 log.debug("Stopping vm %s" % label)
196
197 vm_info = self.db.view_machine_by_label(label)
198
199 if self._status(vm_info.name) == self.STOPPED:
200 raise CuckooMachineError("Trying to stop an already stopped vm %s" % label)
201
202 proc = self.state.get(vm_info.name, None)
203 proc.kill()
204
205 stop_me = 0
206 while proc.poll() is None:
207 if stop_me < int(self.options_globals.timeouts.vm_state):
208 time.sleep(1)
209 stop_me += 1
210 else:
211 log.debug("Stopping vm %s timeouted. Killing" % label)
212 proc.terminate()
213 time.sleep(1)
214
215
216
217
218 self.state[vm_info.name] = None
219
221 """Gets current status of a vm.
222 @param name: virtual machine name.
223 @return: status string.
224 """
225 p = self.state.get(name, None)
226 if p is not None:
227 return self.RUNNING
228 return self.STOPPED
229