Skip to content

Commit 63489c1

Browse files
committed
q-dev: Set.required -> Set.assignment
1 parent d62624f commit 63489c1

File tree

7 files changed

+119
-66
lines changed

7 files changed

+119
-66
lines changed

Makefile

+5-5
Original file line numberDiff line numberDiff line change
@@ -66,31 +66,31 @@ ADMIN_API_METHODS_SIMPLE = \
6666
admin.vm.device.pci.Attached \
6767
admin.vm.device.pci.Available \
6868
admin.vm.device.pci.Detach \
69-
admin.vm.device.pci.Set.required \
69+
admin.vm.device.pci.Set.assignment \
7070
admin.vm.device.pci.Unassign \
7171
admin.vm.device.block.Assign \
7272
admin.vm.device.block.Assigned \
7373
admin.vm.device.block.Attach \
7474
admin.vm.device.block.Attached \
7575
admin.vm.device.block.Available \
7676
admin.vm.device.block.Detach \
77-
admin.vm.device.block.Set.required \
77+
admin.vm.device.block.Set.assignment \
7878
admin.vm.device.block.Unassign \
7979
admin.vm.device.usb.Assign \
8080
admin.vm.device.usb.Assigned \
8181
admin.vm.device.usb.Attach \
8282
admin.vm.device.usb.Attached \
8383
admin.vm.device.usb.Available \
8484
admin.vm.device.usb.Detach \
85-
admin.vm.device.usb.Set.required \
85+
admin.vm.device.usb.Set.assignment \
8686
admin.vm.device.usb.Unassign \
8787
admin.vm.device.mic.Assign \
8888
admin.vm.device.mic.Assigned \
8989
admin.vm.device.mic.Attach \
9090
admin.vm.device.mic.Attached \
9191
admin.vm.device.mic.Available \
9292
admin.vm.device.mic.Detach \
93-
admin.vm.device.mic.Set.required \
93+
admin.vm.device.mic.Set.assignment \
9494
admin.vm.device.mic.Unassign \
9595
admin.vm.feature.CheckWithNetvm \
9696
admin.vm.feature.CheckWithTemplate \
@@ -227,7 +227,7 @@ endif
227227
admin.vm.device.testclass.Unassign \
228228
admin.vm.device.testclass.Attached \
229229
admin.vm.device.testclass.Assigned \
230-
admin.vm.device.testclass.Set.required \
230+
admin.vm.device.testclass.Set.assignment \
231231
admin.vm.device.testclass.Available
232232
install -d $(DESTDIR)/etc/qubes/policy.d/include
233233
install -m 0644 qubes-rpc-policy/admin-local-ro \

qubes-rpc-policy/90-admin-default.policy.header

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@
2626
!include-service admin.vm.device.mic.Attached * include/admin-local-ro
2727
!include-service admin.vm.device.mic.Available * include/admin-local-ro
2828
!include-service admin.vm.device.mic.Detach * include/admin-local-rwx
29-
!include-service admin.vm.device.mic.Set.required * include/admin-local-rwx
29+
!include-service admin.vm.device.mic.Set.assignment * include/admin-local-rwx
3030
!include-service admin.vm.device.mic.Unassign * include/admin-local-rwx
3131
!include-service admin.vm.device.usb.Assign * include/admin-local-rwx
3232
!include-service admin.vm.device.usb.Assigned * include/admin-local-ro
3333
!include-service admin.vm.device.usb.Attach * include/admin-local-rwx
3434
!include-service admin.vm.device.usb.Attached * include/admin-local-ro
3535
!include-service admin.vm.device.usb.Available * include/admin-local-ro
3636
!include-service admin.vm.device.usb.Detach * include/admin-local-rwx
37-
!include-service admin.vm.device.usb.Set.required * include/admin-local-rwx
37+
!include-service admin.vm.device.usb.Set.assignment * include/admin-local-rwx
3838
!include-service admin.vm.device.usb.Unassign * include/admin-local-rwx
3939

qubes/api/admin.py

+12-9
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
import qubes.vm.adminvm
4747
import qubes.vm.qubesvm
4848
from qubes.device_protocol import (
49-
VirtualDevice, UnknownDevice, DeviceAssignment)
49+
VirtualDevice, UnknownDevice, DeviceAssignment, AssignmentMode)
5050

5151

5252
class QubesMgmtEventsDispatcher:
@@ -1398,7 +1398,7 @@ async def vm_device_detach(self, endpoint):
13981398

13991399
# Assign/Unassign action can modify only a persistent state of running VM.
14001400
# For this reason, write=True
1401-
@qubes.api.method('admin.vm.device.{endpoint}.Set.required',
1401+
@qubes.api.method('admin.vm.device.{endpoint}.Set.assignment',
14021402
endpoints=(ep.name
14031403
for ep in importlib.metadata.entry_points(group='qubes.devices')),
14041404
scope='local', write=True)
@@ -1412,17 +1412,20 @@ async def vm_device_set_required(self, endpoint, untrusted_payload):
14121412
"""
14131413
devclass = endpoint
14141414

1415-
self.enforce(untrusted_payload in (b'True', b'False'))
1416-
# now is safe to eval, since the value of untrusted_payload is trusted
1417-
# pylint: disable=eval-used
1418-
assignment = eval(untrusted_payload)
1419-
del untrusted_payload
1415+
allowed_values = {
1416+
b'required': AssignmentMode.REQUIRED,
1417+
b'ask-to-attach': AssignmentMode.ASK,
1418+
b'auto-attach': AssignmentMode.AUTO}
1419+
try:
1420+
mode = allowed_values[untrusted_payload]
1421+
except KeyError:
1422+
raise qubes.exc.PermissionDenied()
14201423

14211424
dev = VirtualDevice.from_qarg(self.arg, devclass, self.app.domains)
14221425

1423-
self.fire_event_for_permission(device=dev, mode=assignment)
1426+
self.fire_event_for_permission(device=dev, mode=mode)
14241427

1425-
await self.dest.devices[devclass].update_required(dev, assignment)
1428+
await self.dest.devices[devclass].update_assignment(dev, mode)
14261429
self.app.save()
14271430

14281431
@qubes.api.method('admin.vm.firewall.Get', no_payload=True,

qubes/devices.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@
6464
import qubes.exc
6565
import qubes.utils
6666
from qubes.device_protocol import (Port, DeviceInfo, UnknownDevice,
67-
DeviceAssignment, VirtualDevice)
67+
DeviceAssignment, VirtualDevice,
68+
AssignmentMode)
6869

6970

7071
DEVICE_DENY_LIST = "/etc/qubes/device-deny.list"
@@ -257,14 +258,14 @@ def load_assignment(self, device_assignment: DeviceAssignment):
257258
assert device_assignment.attach_automatically
258259
self._set.add(device_assignment)
259260

260-
async def update_required(self, device: VirtualDevice, required: bool):
261+
async def update_assignment(
262+
self, device: VirtualDevice, mode: AssignmentMode
263+
):
261264
"""
262265
Update `required` flag of an already attached device.
263266
264267
:param VirtualDevice device: device for which change required flag
265-
:param bool required: new assignment:
266-
`False` -> device will be auto-attached to qube
267-
`True` -> device is required to start qube
268+
:param AssignmentMode mode: new assignment mode
268269
"""
269270
if self._vm.is_halted():
270271
raise qubes.exc.QubesVMNotStartedError(
@@ -281,11 +282,10 @@ async def update_required(self, device: VirtualDevice, required: bool):
281282

282283
# be careful to use already present assignment, not the provided one
283284
# - to not change options as a side effect
284-
if assignment.required == required:
285+
if assignment.mode == mode:
285286
return
286287

287-
new_assignment = assignment.clone(
288-
mode='required' if required else 'auto-attach')
288+
new_assignment = assignment.clone(mode=mode)
289289
self._set.discard(assignment)
290290
self._set.add(new_assignment)
291291
await self._vm.fire_event_async(

qubes/tests/api_admin.py

+45-27
Original file line numberDiff line numberDiff line change
@@ -2992,7 +2992,7 @@ def test_642_vm_create_disposable_not_allowed(self, storage_mock):
29922992
b'test-vm1')
29932993
self.assertFalse(self.app.save.called)
29942994

2995-
def test_650_vm_device_set_required_true(self):
2995+
def test_650_vm_device_set_mode_required(self):
29962996
assignment = DeviceAssignment(VirtualDevice(Port(
29972997
self.vm, '1234', 'testclass'), device_id='bee'),
29982998
mode='auto-attach', options={'opt1': 'value'})
@@ -3006,24 +3006,25 @@ def test_650_vm_device_set_required_true(self):
30063006
with unittest.mock.patch.object(qubes.vm.qubesvm.QubesVM,
30073007
'is_halted', lambda _: False):
30083008
value = self.call_mgmt_func(
3009-
b'admin.vm.device.testclass.Set.required',
3010-
b'test-vm1', b'test-vm1+1234:bee', b'True')
3009+
b'admin.vm.device.testclass.Set.assignment',
3010+
b'test-vm1', b'test-vm1+1234:bee', b'required')
30113011

30123012
self.assertIsNone(value)
30133013
dev = DeviceInfo(Port(
30143014
self.vm, '1234', 'testclass'), device_id='bee')
3015-
required = self.vm.devices['testclass'].get_assigned_devices(
3016-
required_only=True)
3015+
required = list(self.vm.devices['testclass'].get_assigned_devices(
3016+
required_only=True))
30173017
self.assertIn(dev, required)
3018+
self.assertEqual(required[0].mode.value, "required")
30183019
self.assertEventFired(
30193020
self.emitter,
3020-
'admin-permission:admin.vm.device.testclass.Set.required')
3021+
'admin-permission:admin.vm.device.testclass.Set.assignment')
30213022
mock_action.assert_called_once_with(
30223023
self.vm, f'device-assignment-changed:testclass',
30233024
device=assignment.virtual_device)
30243025
self.app.save.assert_called_once_with()
30253026

3026-
def test_651_vm_device_set_required_false(self):
3027+
def test_651_vm_device_set_mode_ask(self):
30273028
assignment = DeviceAssignment(VirtualDevice(Port(
30283029
self.vm, '1234', 'testclass'), device_id='bee'),
30293030
mode='required', options={'opt1': 'value'})
@@ -3037,83 +3038,100 @@ def test_651_vm_device_set_required_false(self):
30373038
with unittest.mock.patch.object(qubes.vm.qubesvm.QubesVM,
30383039
'is_halted', lambda _: False):
30393040
value = self.call_mgmt_func(
3040-
b'admin.vm.device.testclass.Set.required',
3041-
b'test-vm1', b'test-vm1+1234:bee', b'False')
3041+
b'admin.vm.device.testclass.Set.assignment',
3042+
b'test-vm1', b'test-vm1+1234:bee', b'ask-to-attach')
30423043

30433044
self.assertIsNone(value)
30443045
dev = DeviceInfo(Port(self.vm, '1234', 'testclass'),
30453046
device_id='bee')
30463047
required = self.vm.devices['testclass'].get_assigned_devices(
30473048
required_only=True)
30483049
self.assertNotIn(dev, required)
3050+
assignments = list(self.vm.devices['testclass'].get_assigned_devices())
3051+
self.assertEqual(assignments[0].mode.value, "ask-to-attach")
30493052
self.assertEventFired(
30503053
self.emitter,
3051-
'admin-permission:admin.vm.device.testclass.Set.required')
3054+
'admin-permission:admin.vm.device.testclass.Set.assignment')
30523055
mock_action.assert_called_once_with(
30533056
self.vm, f'device-assignment-changed:testclass',
30543057
device=assignment.virtual_device)
30553058
self.app.save.assert_called_once_with()
30563059

3057-
def test_652_vm_device_set_required_true_unchanged(self):
3060+
def test_652_vm_device_set_mode_auto(self):
30583061
assignment = DeviceAssignment(VirtualDevice(Port(
30593062
self.vm, '1234', 'testclass'), device_id='bee'),
30603063
mode='required', options={'opt1': 'value'})
30613064
self.loop.run_until_complete(
30623065
self.vm.devices['testclass'].assign(assignment))
3066+
mock_action = unittest.mock.Mock()
3067+
mock_action.return_value = None
3068+
del mock_action._is_coroutine
3069+
self.vm.add_handler(f'device-assignment-changed:testclass', mock_action)
3070+
30633071
with unittest.mock.patch.object(qubes.vm.qubesvm.QubesVM,
30643072
'is_halted', lambda _: False):
30653073
value = self.call_mgmt_func(
3066-
b'admin.vm.device.testclass.Set.required',
3067-
b'test-vm1', b'test-vm1+1234:bee', b'True')
3074+
b'admin.vm.device.testclass.Set.assignment',
3075+
b'test-vm1', b'test-vm1+1234:bee', b'auto-attach')
3076+
30683077
self.assertIsNone(value)
30693078
dev = DeviceInfo(Port(self.vm, '1234', 'testclass'),
30703079
device_id='bee')
30713080
required = self.vm.devices['testclass'].get_assigned_devices(
30723081
required_only=True)
3073-
self.assertIn(dev, required)
3082+
self.assertNotIn(dev, required)
3083+
assignments = list(self.vm.devices['testclass'].get_assigned_devices())
3084+
self.assertEqual(assignments[0].mode.value, "auto-attach")
3085+
self.assertEventFired(
3086+
self.emitter,
3087+
'admin-permission:admin.vm.device.testclass.Set.assignment')
3088+
mock_action.assert_called_once_with(
3089+
self.vm, f'device-assignment-changed:testclass',
3090+
device=assignment.virtual_device)
30743091
self.app.save.assert_called_once_with()
30753092

3076-
def test_653_vm_device_set_required_false_unchanged(self):
3093+
def test_653_vm_device_set_mode_unchanged(self):
30773094
assignment = DeviceAssignment(VirtualDevice(Port(
3078-
self.vm, '1234', 'testclass')),
3079-
mode='auto-attach', options={'opt1': 'value'})
3095+
self.vm, '1234', 'testclass'), device_id='bee'),
3096+
mode='required', options={'opt1': 'value'})
30803097
self.loop.run_until_complete(
30813098
self.vm.devices['testclass'].assign(assignment))
30823099
with unittest.mock.patch.object(qubes.vm.qubesvm.QubesVM,
30833100
'is_halted', lambda _: False):
30843101
value = self.call_mgmt_func(
3085-
b'admin.vm.device.testclass.Set.required',
3086-
b'test-vm1', b'test-vm1+1234', b'False')
3102+
b'admin.vm.device.testclass.Set.assignment',
3103+
b'test-vm1', b'test-vm1+1234:bee', b'required')
30873104
self.assertIsNone(value)
3088-
dev = qubes.device_protocol.DeviceInfo(Port(self.vm, '1234', 'testclass'))
3105+
dev = DeviceInfo(Port(self.vm, '1234', 'testclass'),
3106+
device_id='bee')
30893107
required = self.vm.devices['testclass'].get_assigned_devices(
30903108
required_only=True)
3091-
self.assertNotIn(dev, required)
3109+
self.assertIn(dev, required)
30923110
self.app.save.assert_called_once_with()
30933111

3094-
def test_654_vm_device_set_persistent_not_assigned(self):
3112+
def test_654_vm_device_set_mode_not_assigned(self):
30953113
self.vm.add_handler('device-list:testclass',
30963114
self.device_list_testclass)
30973115
with unittest.mock.patch.object(qubes.vm.qubesvm.QubesVM,
30983116
'is_halted', lambda _: False):
30993117
with self.assertRaises(qubes.exc.QubesValueError):
31003118
self.call_mgmt_func(
3101-
b'admin.vm.device.testclass.Set.required',
3102-
b'test-vm1', b'test-vm1+1234', b'True')
3119+
b'admin.vm.device.testclass.Set.assignment',
3120+
b'test-vm1', b'test-vm1+1234', b'required')
31033121
dev = qubes.device_protocol.DeviceInfo(Port(self.vm, '1234', 'testclass'))
31043122
self.assertNotIn(
31053123
dev, self.vm.devices['testclass'].get_assigned_devices())
31063124
self.assertFalse(self.app.save.called)
31073125

3108-
def test_655_vm_device_set_persistent_invalid_value(self):
3126+
def test_655_vm_device_set_mode_invalid_value(self):
31093127
self.vm.add_handler('device-list:testclass',
31103128
self.device_list_testclass)
31113129
with unittest.mock.patch.object(qubes.vm.qubesvm.QubesVM,
31123130
'is_halted', lambda _: False):
31133131
with self.assertRaises(qubes.exc.PermissionDenied):
31143132
self.call_mgmt_func(
3115-
b'admin.vm.device.testclass.Set.required',
3116-
b'test-vm1', b'test-vm1+1234', b'maybe')
3133+
b'admin.vm.device.testclass.Set.assignment',
3134+
b'test-vm1', b'test-vm1+1234', b'True')
31173135
dev = qubes.device_protocol.DeviceInfo(Port(self.vm, '1234', 'testclass'))
31183136
self.assertNotIn(dev, self.vm.devices['testclass'].get_assigned_devices())
31193137
self.assertFalse(self.app.save.called)

0 commit comments

Comments
 (0)