From 732e291ab6b86b370b36a8e2dbb98a4a6118add9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Pierret=20=28fepitre=29?= Date: Tue, 17 Mar 2020 15:39:38 +0100 Subject: [PATCH 1/4] gui: drop legacy qubes-keyboard support Add check for keyboard-layout feature set --- qubes/ext/gui.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/qubes/ext/gui.py b/qubes/ext/gui.py index e542a360..feacb221 100644 --- a/qubes/ext/gui.py +++ b/qubes/ext/gui.py @@ -21,8 +21,11 @@ # License along with this library; if not, see . # +import re + import qubes.config import qubes.ext +import qubes.exc class GUI(qubes.ext.Extension): @@ -96,16 +99,6 @@ class GUI(qubes.ext.Extension): if kbd_layout: vm.untrusted_qdb.write('/keyboard-layout', kbd_layout) - # Legacy value for setting keyboard layout - xkb_keymap = \ - 'xkb_keymap {\x0a\x09xkb_keycodes { include ' \ - '"evdev"\x09};\x0a\x09xkb_types { include ' \ - '"complete"\x09};\x0a\x09xkb_compat { include ' \ - '"complete"\x09};\x0a\x09xkb_symbols { include ' \ - '"pc+%s+inet(evdev)"\x09};\x0a\x09xkb_geometry ' \ - '{ include "pc(pc105)"\x09};\x0a};' % kbd_layout - vm.untrusted_qdb.write('/qubes-keyboard', xkb_keymap) - # Set GuiVM prefix guivm_windows_prefix = vm.features.get('guivm-windows-prefix', 'GuiVM') if vm.features.get('service.guivm-gui-agent', None): @@ -128,3 +121,21 @@ class GUI(qubes.ext.Extension): for attached_vm in attached_vms: attached_vm.untrusted_qdb.write('/qubes-gui-domain-xid', str(vm.xid)) + + @qubes.ext.handler('domain-feature-pre-set:keyboard-layout') + def on_feature_pre_set(self, subject, event, feature, value, oldvalue=None): + untrusted_xkb_layout = value.split('+') + if not len(untrusted_xkb_layout) == 3: + raise qubes.exc.QubesValueError + + untrusted_layout = untrusted_xkb_layout[0] + untrusted_variant = untrusted_xkb_layout[1] + untrusted_options = untrusted_xkb_layout[2] + + re_variant = '^[a-zA-Z0-9-_]+$' + re_options = '^[a-zA-Z0-9-_:,]+$' + + if not untrusted_layout.isalpha() or \ + not bool(re.match(re_variant, untrusted_variant)) or \ + not bool(re.match(re_options, untrusted_options)): + raise qubes.exc.QubesValueError From 5cb0e61a84d186e1613a10467192bfe72c4c077b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Pierret=20=28fepitre=29?= Date: Tue, 17 Mar 2020 15:44:36 +0100 Subject: [PATCH 2/4] tests: adapt tests for keyboard-layout --- qubes/tests/vm/qubesvm.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/qubes/tests/vm/qubesvm.py b/qubes/tests/vm/qubesvm.py index 2f27cb13..6c1d997a 100644 --- a/qubes/tests/vm/qubesvm.py +++ b/qubes/tests/vm/qubesvm.py @@ -1832,14 +1832,7 @@ class TC_90_QubesVM(QubesVMTestsMixin, qubes.tests.QubesTestCase): name='appvm', qid=3) vm.netvm = None vm.guivm = guivm - guivm.features['keyboard-layout'] = 'fr' - xkb_keymap = \ - 'xkb_keymap {\x0a\x09xkb_keycodes { include ' \ - '"evdev"\x09};\x0a\x09xkb_types { include ' \ - '"complete"\x09};\x0a\x09xkb_compat { include ' \ - '"complete"\x09};\x0a\x09xkb_symbols { include ' \ - '"pc+fr+inet(evdev)"\x09};\x0a\x09xkb_geometry ' \ - '{ include "pc(pc105)"\x09};\x0a};' + guivm.features['keyboard-layout'] = 'fr++' guivm.is_running = lambda: True vm.events_enabled = True test_qubesdb = TestQubesDB() @@ -1851,8 +1844,7 @@ class TC_90_QubesVM(QubesVMTestsMixin, qubes.tests.QubesTestCase): '/name': 'test-inst-appvm', '/type': 'AppVM', '/default-user': 'user', - '/qubes-keyboard': xkb_keymap, - '/keyboard-layout': 'fr', + '/keyboard-layout': 'fr++', '/qubes-vm-type': 'AppVM', '/qubes-gui-domain-xid': '{}'.format(guivm.xid), '/qubes-debug-mode': '0', @@ -1918,6 +1910,22 @@ class TC_90_QubesVM(QubesVMTestsMixin, qubes.tests.QubesTestCase): '/connected-ips6': '', }) + @unittest.mock.patch('qubes.utils.get_timezone') + @unittest.mock.patch('qubes.utils.urandom') + @unittest.mock.patch('qubes.vm.qubesvm.QubesVM.untrusted_qdb') + def test_624_qdb_guivm_invalid_keyboard_layout(self, mock_qubesdb, + mock_urandom, mock_timezone): + mock_urandom.return_value = b'A' * 64 + mock_timezone.return_value = 'UTC' + template = self.get_vm( + cls=qubes.vm.templatevm.TemplateVM, name='template') + guivm = self.get_vm(cls=qubes.vm.appvm.AppVM, template=template, + name='sys-gui', qid=2, provides_network=False) + guivm.is_running = lambda: True + guivm.events_enabled = True + with self.assertRaises(qubes.exc.QubesValueError): + guivm.features['keyboard-layout'] = 'fr123++' + @asyncio.coroutine def coroutine_mock(self, mock, *args, **kwargs): return mock(*args, **kwargs) From f130ec0bf333bc4a29bd27f50955e37d23a8d396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Pierret=20=28fepitre=29?= Date: Wed, 18 Mar 2020 09:46:21 +0100 Subject: [PATCH 3/4] gui: improvements of feature keyboard layout checks --- qubes/ext/gui.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/qubes/ext/gui.py b/qubes/ext/gui.py index feacb221..35ff5902 100644 --- a/qubes/ext/gui.py +++ b/qubes/ext/gui.py @@ -126,16 +126,18 @@ class GUI(qubes.ext.Extension): def on_feature_pre_set(self, subject, event, feature, value, oldvalue=None): untrusted_xkb_layout = value.split('+') if not len(untrusted_xkb_layout) == 3: - raise qubes.exc.QubesValueError + raise qubes.exc.QubesValueError("Invalid number of parameters") untrusted_layout = untrusted_xkb_layout[0] untrusted_variant = untrusted_xkb_layout[1] untrusted_options = untrusted_xkb_layout[2] - re_variant = '^[a-zA-Z0-9-_]+$' - re_options = '^[a-zA-Z0-9-_:,]+$' + re_variant = r'^[a-zA-Z0-9-_]*$' + re_options = r'^[a-zA-Z0-9-_:,]*$' - if not untrusted_layout.isalpha() or \ - not bool(re.match(re_variant, untrusted_variant)) or \ - not bool(re.match(re_options, untrusted_options)): - raise qubes.exc.QubesValueError + if not untrusted_layout.isalpha(): + raise qubes.exc.QubesValueError("Invalid layout provided") + if not bool(re.match(re_variant, untrusted_variant)): + raise qubes.exc.QubesValueError("Invalid variant provided") + if not bool(re.match(re_options, untrusted_options)): + raise qubes.exc.QubesValueError("Invalid options provided") From 577e4b24a6b039af32285b323d57197eb7a8440f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Pierret=20=28fepitre=29?= Date: Wed, 18 Mar 2020 14:17:04 +0100 Subject: [PATCH 4/4] gui: fixes from Marek's comments --- qubes/ext/gui.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qubes/ext/gui.py b/qubes/ext/gui.py index 35ff5902..dc61e888 100644 --- a/qubes/ext/gui.py +++ b/qubes/ext/gui.py @@ -125,7 +125,7 @@ class GUI(qubes.ext.Extension): @qubes.ext.handler('domain-feature-pre-set:keyboard-layout') def on_feature_pre_set(self, subject, event, feature, value, oldvalue=None): untrusted_xkb_layout = value.split('+') - if not len(untrusted_xkb_layout) == 3: + if len(untrusted_xkb_layout) != 3: raise qubes.exc.QubesValueError("Invalid number of parameters") untrusted_layout = untrusted_xkb_layout[0] @@ -137,7 +137,7 @@ class GUI(qubes.ext.Extension): if not untrusted_layout.isalpha(): raise qubes.exc.QubesValueError("Invalid layout provided") - if not bool(re.match(re_variant, untrusted_variant)): + if not re.match(re_variant, untrusted_variant): raise qubes.exc.QubesValueError("Invalid variant provided") - if not bool(re.match(re_options, untrusted_options)): + if not re.match(re_options, untrusted_options): raise qubes.exc.QubesValueError("Invalid options provided")