Use QubesDB instead of Xenstore.

Mostly done. Things still using xenstore/not working at all:
 - DispVM
 - qubesutils.py (especially qvm-block and qvm-usb code)
 - external IP change notification for ProxyVM (should be done via RPC
   service)
This commit is contained in:
Marek Marczykowski 2013-06-07 05:16:15 +02:00 committed by Marek Marczykowski-Górecki
parent 31424603fa
commit f159f3e168
7 changed files with 69 additions and 101 deletions

View File

@ -39,6 +39,7 @@ from qubes import qmemman_algo
import libvirt
import warnings
from qubes.qdb import QubesDB
from qubes.qubes import dry_run,vmm
from qubes.qubes import register_qubes_vm_class
from qubes.qubes import QubesVmCollection,QubesException,QubesHost,QubesVmLabels
@ -292,6 +293,7 @@ class QubesVm(object):
self.__qid = self._qid
self._libvirt_domain = None
self._qdb_connection = None
assert self.__qid < qubes_max_qid, "VM id out of bounds!"
assert self.name is not None
@ -549,6 +551,8 @@ class QubesVm(object):
self.pre_rename(name)
self.libvirt_domain.undefine()
self._libvirt_domain = None
self._qdb_connection.close()
self._qdb_connection = None
new_conf = os.path.join(self.dir_path, name + '.conf')
if os.path.exists(self.conf_file):
@ -641,6 +645,13 @@ class QubesVm(object):
def is_disposablevm(self):
return False
@property
def qdb(self):
if self._qdb_connection is None:
if self.is_running():
self._qdb_connection = QubesDB(self.name)
return self._qdb_connection
@property
def xid(self):
if self.libvirt_domain is None:
@ -926,74 +937,41 @@ class QubesVm(object):
if dry_run:
return
if xid is None:
xid = self.xid
assert xid >= 0, "Invalid XID value"
domain_path = vmm.xs.get_domain_path(xid)
# Set Xen Store entires with VM networking info:
vmm.xs.write('', "{0}/qubes-vm-type".format(domain_path),
self.type)
vmm.xs.write('', "{0}/qubes-vm-updateable".format(domain_path),
str(self.updateable))
self.qdb.write("/name", self.name)
self.qdb.write("/qubes-vm-type", self.type)
self.qdb.write("/qubes-vm-updateable", str(self.updateable))
if self.is_netvm():
vmm.xs.write('',
"{0}/qubes-netvm-gateway".format(domain_path),
self.gateway)
vmm.xs.write('',
"{0}/qubes-netvm-secondary-dns".format(domain_path),
self.secondary_dns)
vmm.xs.write('',
"{0}/qubes-netvm-netmask".format(domain_path),
self.netmask)
vmm.xs.write('',
"{0}/qubes-netvm-network".format(domain_path),
self.network)
self.qdb.write("/qubes-netvm-gateway", self.gateway)
self.qdb.write("/qubes-netvm-secondary-dns", self.secondary_dns)
self.qdb.write("/qubes-netvm-netmask", self.netmask)
self.qdb.write("/qubes-netvm-network", self.network)
if self.netvm is not None:
vmm.xs.write('', "{0}/qubes-ip".format(domain_path), self.ip)
vmm.xs.write('', "{0}/qubes-netmask".format(domain_path),
self.netvm.netmask)
vmm.xs.write('', "{0}/qubes-gateway".format(domain_path),
self.netvm.gateway)
vmm.xs.write('',
"{0}/qubes-secondary-dns".format(domain_path),
self.netvm.secondary_dns)
self.qdb.write("/qubes-ip", self.ip)
self.qdb.write("/qubes-netmask", self.netvm.netmask)
self.qdb.write("/qubes-gateway", self.netvm.gateway)
self.qdb.write("/qubes-secondary-dns", self.netvm.secondary_dns)
tzname = self.get_timezone()
if tzname:
vmm.xs.write('',
"{0}/qubes-timezone".format(domain_path),
tzname)
self.qdb.write("/qubes-timezone", tzname)
for srv in self.services.keys():
# convert True/False to "1"/"0"
vmm.xs.write('', "{0}/qubes-service/{1}".format(domain_path, srv),
self.qdb.write("/qubes-service/{0}".format(srv),
str(int(self.services[srv])))
vmm.xs.write('',
"{0}/qubes-block-devices".format(domain_path),
'')
self.qdb.write("/qubes-block-devices", '')
vmm.xs.write('',
"{0}/qubes-usb-devices".format(domain_path),
'')
self.qdb.write("/qubes-usb-devices", '')
vmm.xs.write('', "{0}/qubes-debug-mode".format(domain_path),
str(int(self.debug)))
self.qdb.write("/qubes-debug-mode", str(int(self.debug)))
# Fix permissions
vmm.xs.set_permissions('', '{0}/device'.format(domain_path),
[{ 'dom': xid }])
vmm.xs.set_permissions('', '{0}/memory'.format(domain_path),
[{ 'dom': xid }])
vmm.xs.set_permissions('', '{0}/qubes-block-devices'.format(domain_path),
[{ 'dom': xid }])
vmm.xs.set_permissions('', '{0}/qubes-usb-devices'.format(domain_path),
# TODO: Currently whole qmemman is quite Xen-specific, so stay with
# xenstore for it until decided otherwise
vmm.xs.set_permissions('', '/local/domain/{0}/memory'.format(self.xid),
[{ 'dom': xid }])
# fire hooks
@ -1712,6 +1690,15 @@ class QubesVm(object):
if (retcode != 0) :
raise OSError ("Cannot execute qrexec-daemon!")
def start_qubesdb(self):
retcode = subprocess.call ([
system_path["qubesdb_daemon_path"],
str(self.xid),
self.name])
if retcode != 0:
self.force_shutdown()
raise OSError("ERROR: Cannot execute qubesdb-daemon!")
def start(self, verbose = False, preparing_dvm = False, start_guid = True,
notify_function = None, mem_required = None):
if dry_run:
@ -1754,12 +1741,16 @@ class QubesVm(object):
self.libvirt_domain.createWithFlags(libvirt.VIR_DOMAIN_START_PAUSED)
if verbose:
print >> sys.stderr, "--> Starting Qubes DB..."
self.start_qubesdb()
xid = self.xid
if preparing_dvm:
self.services['qubes-dvm'] = True
if verbose:
print >> sys.stderr, "--> Setting Xen Store info for the VM..."
print >> sys.stderr, "--> Setting Qubes DB info for the VM..."
self.create_xenstore_entries(xid)
qvm_collection = QubesVmCollection()

View File

@ -106,35 +106,10 @@ class QubesNetVm(QubesVm):
assert lo >= 1 and lo <= 254, "Wrong IP address for VM"
return self.dispnetprefix + "{0}".format(lo)
def create_xenstore_entries(self, xid = None):
if dry_run:
return
if xid is None:
xid = self.xid
super(QubesNetVm, self).create_xenstore_entries(xid)
vmm.xs.write('', "/local/domain/{0}/qubes-netvm-external-ip".format(xid), '')
self.update_external_ip_permissions(xid)
def update_external_ip_permissions(self, xid = -1):
if xid < 0:
xid = self.get_xid()
if xid < 0:
return
perms = [ { 'dom': xid } ]
for xid in self.__external_ip_allowed_xids:
perms.append({ 'dom': xid, 'read': True })
try:
vmm.xs.set_permissions('', '/local/domain/{0}/qubes-netvm-external-ip'.format(xid),
perms)
except xen.lowlevel.xs.Error as e:
print >>sys.stderr, "WARNING: failed to update external IP " \
"permissions: %s" % (str(e))
# TODO: VMs in __external_ip_allowed_xids should be notified via RPC
# service on exteran IP change
pass
def start(self, **kwargs):
if dry_run:

View File

@ -99,9 +99,7 @@ class QubesProxyVm(QubesNetVm):
super(QubesProxyVm, self).create_xenstore_entries(xid)
vmm.xs.write('', "/local/domain/{0}/qubes-iptables-error".format(xid), '')
vmm.xs.set_permissions('', "/local/domain/{0}/qubes-iptables-error".format(xid),
[{ 'dom': xid, 'write': True }])
self.qdb.write("/qubes-iptables-error", '')
self.write_iptables_xenstore_entry()
def write_netvm_domid_entry(self, xid = -1):
@ -112,14 +110,14 @@ class QubesProxyVm(QubesNetVm):
xid = self.get_xid()
if self.netvm is None:
vmm.xs.write('', "/local/domain/{0}/qubes-netvm-domid".format(xid), '')
self.qdb.write("/qubes-netvm-domid", '')
else:
vmm.xs.write('', "/local/domain/{0}/qubes-netvm-domid".format(xid),
self.qdb.write("/qubes-netvm-domid",
"{0}".format(self.netvm.get_xid()))
def write_iptables_xenstore_entry(self):
vmm.xs.rm('', "/local/domain/{0}/qubes-iptables-domainrules".format(self.get_xid()))
iptables = "# Generated by Qubes Core on {0}\n".format(datetime.now().ctime())
self.qdb.rm("/qubes-iptables-domainrules/")
iptables = "# Generated by Qubes Core on \n".format(datetime.now().ctime())
iptables += "*filter\n"
iptables += ":INPUT DROP [0:0]\n"
iptables += ":FORWARD DROP [0:0]\n"
@ -140,7 +138,7 @@ class QubesProxyVm(QubesNetVm):
# Deny inter-VMs networking
iptables += "-A FORWARD -i vif+ -o vif+ -j DROP\n"
iptables += "COMMIT\n"
vmm.xs.write('', "/local/domain/{0}/qubes-iptables-header".format(self.get_xid()), iptables)
self.qdb.write("/qubes-iptables-header", iptables)
vms = [vm for vm in self.connected_vms.values()]
for vm in vms:
@ -168,18 +166,18 @@ class QubesProxyVm(QubesNetVm):
rules_action = accept_action
for rule in conf["rules"]:
iptables += "-A FORWARD -s {0} -d {1}".format(ip, rule["address"])
iptables += "-A FORWARD -s -d {1}".format(ip, rule["address"])
if rule["netmask"] != 32:
iptables += "/{0}".format(rule["netmask"])
iptables += "/".format(rule["netmask"])
if rule["proto"] is not None and rule["proto"] != "any":
iptables += " -p {0}".format(rule["proto"])
iptables += " -p ".format(rule["proto"])
if rule["portBegin"] is not None and rule["portBegin"] > 0:
iptables += " --dport {0}".format(rule["portBegin"])
iptables += " --dport ".format(rule["portBegin"])
if rule["portEnd"] is not None and rule["portEnd"] > rule["portBegin"]:
iptables += ":{0}".format(rule["portEnd"])
iptables += ":".format(rule["portEnd"])
iptables += " -j {0}\n".format(rules_action)
iptables += " -j \n".format(rules_action)
if conf["allowDns"] and self.netvm is not None:
# PREROUTING does DNAT to NetVM DNSes, so we need self.netvm.
@ -193,20 +191,20 @@ class QubesProxyVm(QubesNetVm):
iptables += "-A FORWARD -s {0} -p tcp -d {1} --dport 53 -j " \
"ACCEPT\n".format(ip,self.netvm.secondary_dns)
if conf["allowIcmp"]:
iptables += "-A FORWARD -s {0} -p icmp -j ACCEPT\n".format(ip)
iptables += "-A FORWARD -s -p icmp -j ACCEPT\n".format(ip)
if conf["allowYumProxy"]:
iptables += "-A FORWARD -s {0} -p tcp -d {1} --dport {2} -j ACCEPT\n".format(ip, yum_proxy_ip, yum_proxy_port)
iptables += "-A FORWARD -s -p tcp -d {1} --dport {2} -j ACCEPT\n".format(ip, yum_proxy_ip, yum_proxy_port)
else:
iptables += "-A FORWARD -s {0} -p tcp -d {1} --dport {2} -j DROP\n".format(ip, yum_proxy_ip, yum_proxy_port)
iptables += "-A FORWARD -s -p tcp -d {1} --dport {2} -j DROP\n".format(ip, yum_proxy_ip, yum_proxy_port)
iptables += "-A FORWARD -s {0} -j {1}\n".format(ip, default_action)
iptables += "-A FORWARD -s -j {1}\n".format(ip, default_action)
iptables += "COMMIT\n"
vmm.xs.write('', "/local/domain/"+str(self.get_xid())+"/qubes-iptables-domainrules/"+str(xid), iptables)
self.qdb.write("/qubes-iptables-domainrules/"+str(xid), iptables)
# no need for ending -A FORWARD -j DROP, cause default action is DROP
self.write_netvm_domid_entry()
self.rules_applied = None
vmm.xs.write('', "/local/domain/{0}/qubes-iptables".format(self.get_xid()), 'reload')
self.qdb.write("/qubes-iptables", 'reload')
register_qubes_vm_class(QubesProxyVm)

View File

@ -110,6 +110,7 @@ class QubesDisposableVm(QubesVm):
def create_xenstore_entries(self, xid):
super(QubesDisposableVm, self).create_xenstore_entries(xid)
# TODO!
domain_path = vmm.xs.get_domain_path(xid)
vmm.xs.write('', "{0}/qubes-restore-complete".format(domain_path),

View File

@ -49,6 +49,7 @@ system_path = {
'qubes_guid_path': '/usr/bin/qubes-guid',
'qrexec_daemon_path': '/usr/lib/qubes/qrexec-daemon',
'qrexec_client_path': '/usr/lib/qubes/qrexec-client',
'qubesdb_daemon_path': '/usr/sbin/qubesdb-daemon',
'qubes_base_dir': qubes_base_dir,

View File

@ -1,5 +1,6 @@
[Unit]
Description=Qubes Dom0 startup setup
After=qubes-db-dom0.service
# Cover legacy init.d script
[Service]

View File

@ -48,6 +48,7 @@ Requires(preun): systemd-units
Requires(postun): systemd-units
Requires: python, pciutils, python-inotify, python-daemon
Requires: qubes-core-dom0-linux >= 2.0.24
Requires: qubes-db-dom0
Requires: python-lxml
Requires: python-psutil
# TODO: R: qubes-gui-dom0 >= 2.1.11