Browse Source

Merge remote-tracking branch 'woju/pull/13/head' into core3-devel

Wojtek Porczyk 8 years ago
parent
commit
a615a45ecd
5 changed files with 124 additions and 2 deletions
  1. 3 1
      qubes/app.py
  2. 3 1
      qubes/storage/__init__.py
  3. 113 0
      qubes/storage/domain.py
  4. 4 0
      qubes/vm/qubesvm.py
  5. 1 0
      rpm_spec/core-dom0.spec

+ 3 - 1
qubes/app.py

@@ -702,7 +702,9 @@ class Qubes(qubes.PropertyHolder):
 
         pools_xml = lxml.etree.Element('pools')
         for pool in self.pools.values():
-            pools_xml.append(pool.__xml__())
+            xml = pool.__xml__()
+            if xml is not None:
+                pools_xml.append(xml)
 
         element.append(pools_xml)
 

+ 3 - 1
qubes/storage/__init__.py

@@ -57,13 +57,15 @@ class Volume(object):
     script = None
     usage = 0
 
-    def __init__(self, name, pool, volume_type, vid=None, size=0, **kwargs):
+    def __init__(self, name, pool, volume_type, vid=None, size=0,
+                 removable=False, **kwargs):
         super(Volume, self).__init__(**kwargs)
         self.name = str(name)
         self.pool = str(pool)
         self.vid = vid
         self.size = size
         self.volume_type = volume_type
+        self.removable = removable
 
     def __xml__(self):
         return lxml.etree.Element('volume', **self.config)

+ 113 - 0
qubes/storage/domain.py

@@ -0,0 +1,113 @@
+#!/usr/bin/env python2
+# -*- encoding: utf8 -*-
+#
+# The Qubes OS Project, http://www.qubes-os.org
+#
+# Copyright (C) 2016 Bahtiar `kalkin-` Gadimov <bahtiar@gadimov.de>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+''' Manages block devices in a domain '''
+
+import string
+
+from qubes.storage import Pool, Volume
+
+
+class DomainPool(Pool):
+    ''' This pool manages all the block devices of a domain.
+
+        The devices are queried through :py:module:`qubesdb`
+    '''
+
+    driver = 'domain'
+
+    def __init__(self, vm):
+        self.vm = vm
+        super(DomainPool, self).__init__(name='p_' + vm.name)
+
+    @property
+    def volumes(self):
+        ''' Queries qubesdb and returns volumes for `self.vm` '''
+
+        qdb = self.vm.qdb
+        safe_set = set(string.letters + string.digits + string.punctuation)
+        allowed_attributes = {'desc': string.printable,
+                              'mode': string.letters,
+                              'size': string.digits}
+        if not self.vm.is_running():
+            return []
+        untrusted_qubes_devices = qdb.list('/qubes-block-devices/')
+        # because we get each path 3 x times as
+        # /qubes-block-devices/foo/{desc,mode,size} we need to merge this
+        devices = {}
+        for untrusted_device_path in untrusted_qubes_devices:
+            if not all(c in safe_set for c in untrusted_device_path):
+                msg = ("%s vm's device path name contains unsafe characters. "
+                       "Skipping it.")
+                self.vm.log.warning(msg % self.vm.name)
+                continue
+
+            # name can be trusted because it was checked as a part of
+            # untrusted_device_path check above
+            _, _, name, untrusted_atr = untrusted_device_path.split('/', 4)
+
+            if untrusted_atr in allowed_attributes.keys():
+                atr = untrusted_atr
+            else:
+                msg = ('{!s} has an unknown qubes-block-device atr {!s} '
+                       'Skipping it')
+                self.vm.log.error(msg.format(self.vm.name, untrusted_atr))
+                continue
+
+            untrusted_value = qdb.read(untrusted_device_path)
+            allowed_characters = allowed_attributes[atr]
+            if all(c in allowed_characters for c in untrusted_value):
+                value = untrusted_value
+            else:
+                msg = ("{!s} vm's device path {!s} contains unsafe characters")
+                self.vm.log.error(msg.format(self.vm.name, atr))
+                continue
+
+            if name not in devices.keys():
+                devices[name] = {}
+
+            devices[name][atr] = value
+
+        return [DomainVolume(n, self.name, **atrs)
+                for n, atrs in devices.items()]
+
+    def clone(self, source, target):
+        raise NotImplementedError
+
+    def __xml__(self):
+        return None
+
+
+class DomainVolume(Volume):
+    ''' A volume provided by a block device in an domain '''
+
+    def __init__(self, name, pool, desc, mode, size):
+        if mode == 'w':
+            volume_type = 'read-write'
+        else:
+            volume_type = 'read-only'
+
+        super(DomainVolume, self).__init__(desc,
+                                           pool,
+                                           volume_type,
+                                           vid=name,
+                                           size=size,
+                                           removable=True)

+ 4 - 0
qubes/vm/qubesvm.py

@@ -51,6 +51,8 @@ import qubes.vm
 import qubes.vm.mix.net
 import qubes.tools.qvm_ls
 
+from qubes.storage.domain import DomainPool
+
 qmemman_present = False
 try:
     import qubes.qmemman.client
@@ -530,6 +532,8 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
 
         # Initialize VM image storage class
         self.storage = qubes.storage.Storage(self)
+        vm_pool = DomainPool(self)
+        self.app.pools[vm_pool.name] = vm_pool
 
 
     @qubes.events.handler('property-set:label')

+ 1 - 0
rpm_spec/core-dom0.spec

@@ -234,6 +234,7 @@ fi
 %dir %{python_sitelib}/qubes/storage
 %{python_sitelib}/qubes/storage/__init__.py*
 %{python_sitelib}/qubes/storage/file.py*
+%{python_sitelib}/qubes/storage/domain.py*
 %{python_sitelib}/qubes/storage/kernels.py*
 
 %dir %{python_sitelib}/qubes/tools