瀏覽代碼

qubes/vm: start VM daemons as normal user

This is migration of core2 commits:

commit d0ba43f253c7c260e7552ebee9a403bdc2f4be26
Author: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
Date:   Mon Jun 6 02:21:08 2016 +0200

    core: start guid as normal user even when VM started by root

    Another attempt to avoid permissions-related problems...

    QubesOS/qubes-issues#1768

commit 89d002a031b2b253b0bafc83d15369ecbc3efc08
Author: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
Date:   Mon Jun 6 02:19:51 2016 +0200

    core: use runuser instead of sudo for switching root->user

    There are problems with using sudo in early system startup
    (systemd-logind not running yet, pam_systemd timeouts). Since we don't
    need full session here, runuser is good enough (even better: faster).

commit 2265fd3d52306ec206cafb578bd2afa2e6ad74f3
Author: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
Date:   Sat Jun 4 17:42:24 2016 +0200

    core: start qubesdb as normal user, even when VM is started by root

    On VM start, old qubesdb-daemon is terminated (if still running). In
    practice it happen only at VM startart (shutdown and quickly start
    again). But in that case, if the VM was started by root, such operation
    would fail.
    So when VM is started by root, make sure that qubesdb-daemon will be
    running as normal user (the first user in group 'qubes' - there should
    be only one).

    Fixes QubesOS/qubes-issues#1745
Marek Marczykowski-Górecki 7 年之前
父節點
當前提交
c534b68665
共有 2 個文件被更改,包括 31 次插入8 次删除
  1. 2 2
      qubes/ext/gui.py
  2. 29 6
      qubes/vm/qubesvm.py

+ 2 - 2
qubes/ext/gui.py

@@ -183,7 +183,7 @@ class GUI(qubes.ext.Extension):
         guid_cmd += self.kde_guid_args(vm)
 
         try:
-            subprocess.check_call(guid_cmd)
+            vm.start_daemon(guid_cmd)
         except subprocess.CalledProcessError:
             raise qubes.exc.QubesVMError(vm,
                 'Cannot start qubes-guid for domain {!r}'.format(vm.name))
@@ -246,7 +246,7 @@ class GUI(qubes.ext.Extension):
         guid_cmd += self.kde_guid_args(vm)
 
         try:
-            subprocess.check_call(guid_cmd)
+            vm.start_daemon(guid_cmd)
         except subprocess.CalledProcessError:
             raise qubes.exc.QubesVMError(vm, 'Cannot start gui daemon')
 

+ 29 - 6
qubes/vm/qubesvm.py

@@ -39,6 +39,7 @@ import time
 import uuid
 import warnings
 
+import grp
 import lxml
 import libvirt  # pylint: disable=import-error
 
@@ -926,6 +927,27 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
 
         return qmemman_client
 
+    @staticmethod
+    def start_daemon(command, **kwargs):
+        '''Start a daemon for the VM
+
+        This function take care to run it as appropriate user.
+
+        :param command: command to run (array for
+        :py:meth:`subprocess.check_call`)
+        :param kwargs: args for :py:meth:`subprocess.check_call`
+        :return: None
+        '''
+
+        prefix_cmd = []
+        if os.getuid() == 0:
+            # try to always have VM daemons running as normal user, otherwise
+            # some files (like clipboard) may be created as root and cause
+            # permission problems
+            qubes_group = grp.getgrnam('qubes')
+            prefix_cmd = ['runuser', '-u', qubes_group.gr_mem[0], '--']
+        subprocess.check_call(prefix_cmd + command, **kwargs)
+
     def start_qrexec_daemon(self):
         '''Start qrexec daemon.
 
@@ -946,7 +968,7 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
             qrexec_env['QREXEC_STARTUP_TIMEOUT'] = str(self.qrexec_timeout)
 
         try:
-            subprocess.check_call(
+            self.start_daemon(
                 [qubes.config.system_path["qrexec_daemon_path"]] + qrexec_args,
                 env=qrexec_env)
         except subprocess.CalledProcessError:
@@ -961,11 +983,12 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
         self.log.info('Starting Qubes DB')
 
         # FIXME #1694 #1241
-        retcode = subprocess.call([
-            qubes.config.system_path["qubesdb_daemon_path"],
-            str(self.xid),
-            self.name])
-        if retcode != 0:
+        try:
+            self.start_daemon([
+                qubes.config.system_path["qubesdb_daemon_path"],
+                str(self.xid),
+                self.name])
+        except subprocess.CalledProcessError:
             raise qubes.exc.QubesException('Cannot execute qubesdb-daemon')
 
     def wait_for_session(self):