Skip to content

Commit 85ab8dd

Browse files
committed
firewall: retry qdb.read/multiread() on InterruptedError in remaining call sites
1 parent 9bb1a94 commit 85ab8dd

2 files changed

Lines changed: 85 additions & 4 deletions

File tree

qubesagent/firewall.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,12 @@ def run_user_script(self):
120120

121121
def read_rules(self, target):
122122
"""Read rules from QubesDB and return them as a list of dicts"""
123-
entries = self.qdb.multiread('/qubes-firewall/{}/'.format(target))
123+
while True:
124+
try:
125+
entries = self.qdb.multiread('/qubes-firewall/{}/'.format(target))
126+
break
127+
except InterruptedError:
128+
continue
124129
assert isinstance(entries, dict)
125130
# drop full path
126131
entries = dict(((k.split('/')[3], v.decode())
@@ -193,7 +198,12 @@ def update_handled(self, addr):
193198
User applications may watch these paths for count increases to remain
194199
up to date with QubesDB changes.
195200
"""
196-
cnt = self.qdb.read('/qubes-firewall-handled/{}'.format(addr))
201+
while True:
202+
try:
203+
cnt = self.qdb.read('/qubes-firewall-handled/{}'.format(addr))
204+
break
205+
except InterruptedError:
206+
continue
197207
try:
198208
cnt = int(cnt)
199209
except (TypeError, ValueError):
@@ -289,7 +299,13 @@ def is_ip6(addr):
289299
def log_error(self, msg):
290300
self.log.error(msg)
291301

292-
user = (self.qdb.read('/default-user') or b'user').decode()
302+
while True:
303+
try:
304+
user = (self.qdb.read('/default-user') or b'user').decode()
305+
break
306+
except InterruptedError:
307+
continue
308+
293309
try:
294310
uid = pwd.getpwnam(user).pw_uid
295311
except KeyError:

qubesagent/test_firewall.py

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,4 +594,69 @@ def read_with_interrupt(key):
594594
self.obj, 4)
595595

596596
self.assertEqual(result, ['10.137.0.1', '10.137.0.2'])
597-
self.assertEqual(call_count[0], 2)
597+
self.assertEqual(call_count[0], 2)
598+
599+
def test_read_rules_retries_on_interrupted_error(self):
600+
"""read_rules() must retry qdb.multiread() on InterruptedError."""
601+
self.obj.qdb.entries['/qubes-firewall/10.137.0.2/policy'] = b'drop'
602+
self.obj.qdb.entries['/qubes-firewall/10.137.0.2/0000'] = b'action=accept'
603+
604+
original_multiread = self.obj.qdb.multiread
605+
call_count = [0]
606+
607+
def multiread_with_interrupt(path):
608+
call_count[0] += 1
609+
if call_count[0] == 1:
610+
raise InterruptedError
611+
return original_multiread(path)
612+
613+
self.obj.qdb.multiread = multiread_with_interrupt
614+
615+
result = qubesagent.firewall.FirewallWorker.read_rules(
616+
self.obj, '10.137.0.2')
617+
618+
self.assertEqual(call_count[0], 2)
619+
self.assertIsNotNone(result)
620+
621+
def test_update_handled_retries_on_interrupted_error(self):
622+
"""update_handled() must retry qdb.read() on InterruptedError."""
623+
self.obj.qdb.entries['/qubes-firewall-handled/10.137.0.2'] = b'5'
624+
625+
original_read = self.obj.qdb.read
626+
call_count = [0]
627+
628+
def read_with_interrupt(key):
629+
call_count[0] += 1
630+
if call_count[0] == 1:
631+
raise InterruptedError
632+
return original_read(key)
633+
634+
self.obj.qdb.read = read_with_interrupt
635+
636+
qubesagent.firewall.FirewallWorker.update_handled(
637+
self.obj, '10.137.0.2')
638+
639+
self.assertEqual(call_count[0], 2)
640+
self.assertEqual(
641+
self.obj.qdb.entries['/qubes-firewall-handled/10.137.0.2'], '6')
642+
643+
def test_log_error_retries_on_interrupted_error(self):
644+
"""log_error() must retry qdb.read('/default-user') on InterruptedError."""
645+
self.obj.qdb.entries['/default-user'] = b'user'
646+
647+
original_read = self.obj.qdb.read
648+
call_count = [0]
649+
650+
def read_with_interrupt(key):
651+
call_count[0] += 1
652+
if key == '/default-user' and call_count[0] == 1:
653+
raise InterruptedError
654+
return original_read(key)
655+
656+
self.obj.qdb.read = read_with_interrupt
657+
658+
with patch('subprocess.check_output'):
659+
qubesagent.firewall.FirewallWorker.log_error(
660+
self.obj, 'test error')
661+
662+
self.assertGreaterEqual(call_count[0], 2)

0 commit comments

Comments
 (0)