From f159f3e168d341d188ec1992a6818f248baf694f Mon Sep 17 00:00:00 2001 From: Marek Marczykowski Date: Fri, 7 Jun 2013 05:16:15 +0200 Subject: [PATCH] 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) --- core-modules/000QubesVm.py | 97 +++++++++++++---------------- core-modules/005QubesNetVm.py | 31 +-------- core-modules/006QubesProxyVm.py | 38 ++++++----- core-modules/01QubesDisposableVm.py | 1 + core/qubes.py | 1 + linux/systemd/qubes-core.service | 1 + rpm_spec/core-dom0.spec | 1 + 7 files changed, 69 insertions(+), 101 deletions(-) diff --git a/core-modules/000QubesVm.py b/core-modules/000QubesVm.py index 773719f1..7176afce 100644 --- a/core-modules/000QubesVm.py +++ b/core-modules/000QubesVm.py @@ -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() diff --git a/core-modules/005QubesNetVm.py b/core-modules/005QubesNetVm.py index e0812250..f49a44ae 100644 --- a/core-modules/005QubesNetVm.py +++ b/core-modules/005QubesNetVm.py @@ -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: diff --git a/core-modules/006QubesProxyVm.py b/core-modules/006QubesProxyVm.py index dd180efa..c848308c 100644 --- a/core-modules/006QubesProxyVm.py +++ b/core-modules/006QubesProxyVm.py @@ -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) diff --git a/core-modules/01QubesDisposableVm.py b/core-modules/01QubesDisposableVm.py index c7fdbefa..b3f216c5 100644 --- a/core-modules/01QubesDisposableVm.py +++ b/core-modules/01QubesDisposableVm.py @@ -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), diff --git a/core/qubes.py b/core/qubes.py index 753ca47f..1dae98bf 100755 --- a/core/qubes.py +++ b/core/qubes.py @@ -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, diff --git a/linux/systemd/qubes-core.service b/linux/systemd/qubes-core.service index 1fde9c27..515ae421 100644 --- a/linux/systemd/qubes-core.service +++ b/linux/systemd/qubes-core.service @@ -1,5 +1,6 @@ [Unit] Description=Qubes Dom0 startup setup +After=qubes-db-dom0.service # Cover legacy init.d script [Service] diff --git a/rpm_spec/core-dom0.spec b/rpm_spec/core-dom0.spec index b9195f06..c835d687 100644 --- a/rpm_spec/core-dom0.spec +++ b/rpm_spec/core-dom0.spec @@ -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