Forráskód Böngészése

firewall: use asyncio's call_later instead of systemd to reload rules

When some expiring rules are present, it is necessary to reload firewall
when those rules expire. Previously systemd timer was used to trigger
this action, but since we have own daemon now, it isn't necessary
anymore - use this daemon for that.
Additionally automatically removing expired rules was completely broken
in R4.0.

Fixes QubesOS/qubes-issues#1173
Marek Marczykowski-Górecki 6 éve
szülő
commit
5e89b23288
3 módosított fájl, 22 hozzáadás és 10 törlés
  1. 0 2
      linux/systemd/Makefile
  2. 22 6
      qubes/firewall.py
  3. 0 2
      rpm_spec/core-dom0.spec

+ 0 - 2
linux/systemd/Makefile

@@ -7,8 +7,6 @@ install:
 	mkdir -p $(DESTDIR)$(UNITDIR)
 	mkdir -p $(DESTDIR)$(UNITDIR)
 	cp qubes-core.service $(DESTDIR)$(UNITDIR)
 	cp qubes-core.service $(DESTDIR)$(UNITDIR)
 	cp qubes-vm@.service $(DESTDIR)$(UNITDIR)
 	cp qubes-vm@.service $(DESTDIR)$(UNITDIR)
-	cp qubes-reload-firewall@.service $(DESTDIR)$(UNITDIR)
-	cp qubes-reload-firewall@.timer $(DESTDIR)$(UNITDIR)
 	cp qubes-qmemman.service $(DESTDIR)$(UNITDIR)
 	cp qubes-qmemman.service $(DESTDIR)$(UNITDIR)
 	cp qubesd.service $(DESTDIR)$(UNITDIR)
 	cp qubesd.service $(DESTDIR)$(UNITDIR)
 	install -d $(DESTDIR)$(UNITDIR)/lvm2-pvscan@.service.d
 	install -d $(DESTDIR)$(UNITDIR)/lvm2-pvscan@.service.d

+ 22 - 6
qubes/firewall.py

@@ -22,11 +22,12 @@
 
 
 import datetime
 import datetime
 import string
 import string
-import subprocess
 
 
 import itertools
 import itertools
 import os
 import os
 import socket
 import socket
+
+import asyncio
 import lxml.etree
 import lxml.etree
 
 
 import qubes
 import qubes
@@ -543,10 +544,19 @@ class Firewall(object):
             rule = Rule(xml_rule)
             rule = Rule(xml_rule)
             self.rules.append(rule)
             self.rules.append(rule)
 
 
+    def _expire_rules(self):
+        '''Function called to reload expired rules'''
+        old_rules = self.rules
+        self.load()
+        if self.rules != old_rules:
+            # this will both save rules skipping those expired and trigger
+            # QubesDB update; and possibly schedule another timer
+            self.save()
+
     def save(self):
     def save(self):
         '''Save firewall rules to a file'''
         '''Save firewall rules to a file'''
         firewall_conf = os.path.join(self.vm.dir_path, self.vm.firewall_conf)
         firewall_conf = os.path.join(self.vm.dir_path, self.vm.firewall_conf)
-        expiring_rules_present = False
+        nearest_expire = False
 
 
         xml_root = lxml.etree.Element('firewall', version=str(2))
         xml_root = lxml.etree.Element('firewall', version=str(2))
 
 
@@ -556,7 +566,9 @@ class Firewall(object):
                 if rule.expire and rule.expire.expired:
                 if rule.expire and rule.expire.expired:
                     continue
                     continue
                 else:
                 else:
-                    expiring_rules_present = True
+                    if nearest_expire is None or rule.expire.datetime < \
+                            nearest_expire:
+                        nearest_expire = rule.expire.datetime
             xml_rule = lxml.etree.Element('rule')
             xml_rule = lxml.etree.Element('rule')
             xml_rule.append(rule.xml_properties())
             xml_rule.append(rule.xml_properties())
             xml_rules.append(xml_rule)
             xml_rules.append(xml_rule)
@@ -577,9 +589,13 @@ class Firewall(object):
 
 
         self.vm.fire_event('firewall-changed')
         self.vm.fire_event('firewall-changed')
 
 
-        if expiring_rules_present and not self.vm.app.vmm.offline_mode:
-            subprocess.call(["sudo", "systemctl", "start",
-                             "qubes-reload-firewall@%s.timer" % self.vm.name])
+        if nearest_expire and not self.vm.app.vmm.offline_mode:
+            loop = asyncio.get_event_loop()
+            # by documentation call_at use loop.time() clock, which not
+            # necessary must be the same as time module; calculate delay and
+            # use call_later instead
+            expire_when = nearest_expire - datetime.datetime.now()
+            loop.call_later(expire_when, self._expire_rules)
 
 
     def qdb_entries(self, addr_family=None):
     def qdb_entries(self, addr_family=None):
         '''Return firewall settings serialized for QubesDB entries
         '''Return firewall settings serialized for QubesDB entries

+ 0 - 2
rpm_spec/core-dom0.spec

@@ -399,8 +399,6 @@ fi
 %{_unitdir}/qubes-qmemman.service
 %{_unitdir}/qubes-qmemman.service
 %{_unitdir}/qubes-vm@.service
 %{_unitdir}/qubes-vm@.service
 %{_unitdir}/qubesd.service
 %{_unitdir}/qubesd.service
-%{_unitdir}/qubes-reload-firewall@.service
-%{_unitdir}/qubes-reload-firewall@.timer
 %attr(2770,root,qubes) %dir /var/lib/qubes
 %attr(2770,root,qubes) %dir /var/lib/qubes
 %attr(2770,root,qubes) %dir /var/lib/qubes/vm-templates
 %attr(2770,root,qubes) %dir /var/lib/qubes/vm-templates
 %attr(2770,root,qubes) %dir /var/lib/qubes/appvms
 %attr(2770,root,qubes) %dir /var/lib/qubes/appvms