Do not use assert statement in security logic
This is because assert statement gets optimised out when Python is run with -O flag. This was pointed out to me by audience at PyWaw 76.
This commit is contained in:
parent
39a9e4e422
commit
4e49b951ce
@ -196,6 +196,11 @@ class AbstractQubesAPI(object):
|
|||||||
return apply_filters(iterable,
|
return apply_filters(iterable,
|
||||||
self.fire_event_for_permission(**kwargs))
|
self.fire_event_for_permission(**kwargs))
|
||||||
|
|
||||||
|
def enforce(self, predicate):
|
||||||
|
'''An assert replacement, but works even with optimisations.'''
|
||||||
|
if not predicate:
|
||||||
|
raise PermissionDenied()
|
||||||
|
|
||||||
|
|
||||||
class QubesDaemonProtocol(asyncio.Protocol):
|
class QubesDaemonProtocol(asyncio.Protocol):
|
||||||
buffer_size = 65536
|
buffer_size = 65536
|
||||||
|
@ -98,8 +98,8 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vmclass_list(self):
|
def vmclass_list(self):
|
||||||
'''List all VM classes'''
|
'''List all VM classes'''
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
|
|
||||||
entrypoints = self.fire_event_for_filter(
|
entrypoints = self.fire_event_for_filter(
|
||||||
pkg_resources.iter_entry_points(qubes.vm.VM_ENTRY_POINT))
|
pkg_resources.iter_entry_points(qubes.vm.VM_ENTRY_POINT))
|
||||||
@ -112,7 +112,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_list(self):
|
def vm_list(self):
|
||||||
'''List all the domains'''
|
'''List all the domains'''
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
|
|
||||||
if self.dest.name == 'dom0':
|
if self.dest.name == 'dom0':
|
||||||
domains = self.fire_event_for_filter(self.app.domains)
|
domains = self.fire_event_for_filter(self.app.domains)
|
||||||
@ -137,11 +137,11 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def property_list(self):
|
def property_list(self):
|
||||||
'''List all global properties'''
|
'''List all global properties'''
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
return self._property_list(self.app)
|
return self._property_list(self.app)
|
||||||
|
|
||||||
def _property_list(self, dest):
|
def _property_list(self, dest):
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
|
|
||||||
properties = self.fire_event_for_filter(dest.property_list())
|
properties = self.fire_event_for_filter(dest.property_list())
|
||||||
|
|
||||||
@ -159,7 +159,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def property_get(self):
|
def property_get(self):
|
||||||
'''Get a value of one global property'''
|
'''Get a value of one global property'''
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
return self._property_get(self.app)
|
return self._property_get(self.app)
|
||||||
|
|
||||||
def _property_get(self, dest):
|
def _property_get(self, dest):
|
||||||
@ -203,7 +203,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def property_get_default(self):
|
def property_get_default(self):
|
||||||
'''Get a value of one global property'''
|
'''Get a value of one global property'''
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
return self._property_get_default(self.app)
|
return self._property_get_default(self.app)
|
||||||
|
|
||||||
def _property_get_default(self, dest):
|
def _property_get_default(self, dest):
|
||||||
@ -247,7 +247,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def property_set(self, untrusted_payload):
|
def property_set(self, untrusted_payload):
|
||||||
'''Set property value'''
|
'''Set property value'''
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
return self._property_set(self.app,
|
return self._property_set(self.app,
|
||||||
untrusted_payload=untrusted_payload)
|
untrusted_payload=untrusted_payload)
|
||||||
|
|
||||||
@ -275,7 +275,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def property_help(self):
|
def property_help(self):
|
||||||
'''Get help for one property'''
|
'''Get help for one property'''
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
return self._property_help(self.app)
|
return self._property_help(self.app)
|
||||||
|
|
||||||
def _property_help(self, dest):
|
def _property_help(self, dest):
|
||||||
@ -303,7 +303,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def property_reset(self):
|
def property_reset(self):
|
||||||
'''Reset a property to a default value'''
|
'''Reset a property to a default value'''
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
return self._property_reset(self.app)
|
return self._property_reset(self.app)
|
||||||
|
|
||||||
def _property_reset(self, dest):
|
def _property_reset(self, dest):
|
||||||
@ -319,7 +319,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', read=True)
|
scope='local', read=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_volume_list(self):
|
def vm_volume_list(self):
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
|
|
||||||
volume_names = self.fire_event_for_filter(self.dest.volumes.keys())
|
volume_names = self.fire_event_for_filter(self.dest.volumes.keys())
|
||||||
return ''.join('{}\n'.format(name) for name in volume_names)
|
return ''.join('{}\n'.format(name) for name in volume_names)
|
||||||
@ -328,7 +328,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', read=True)
|
scope='local', read=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_volume_info(self):
|
def vm_volume_info(self):
|
||||||
assert self.arg in self.dest.volumes.keys()
|
self.enforce(self.arg in self.dest.volumes.keys())
|
||||||
|
|
||||||
self.fire_event_for_permission()
|
self.fire_event_for_permission()
|
||||||
|
|
||||||
@ -356,7 +356,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', read=True)
|
scope='local', read=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_volume_listsnapshots(self):
|
def vm_volume_listsnapshots(self):
|
||||||
assert self.arg in self.dest.volumes.keys()
|
self.enforce(self.arg in self.dest.volumes.keys())
|
||||||
|
|
||||||
volume = self.dest.volumes[self.arg]
|
volume = self.dest.volumes[self.arg]
|
||||||
id_to_timestamp = volume.revisions
|
id_to_timestamp = volume.revisions
|
||||||
@ -369,13 +369,13 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', write=True)
|
scope='local', write=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_volume_revert(self, untrusted_payload):
|
def vm_volume_revert(self, untrusted_payload):
|
||||||
assert self.arg in self.dest.volumes.keys()
|
self.enforce(self.arg in self.dest.volumes.keys())
|
||||||
untrusted_revision = untrusted_payload.decode('ascii').strip()
|
untrusted_revision = untrusted_payload.decode('ascii').strip()
|
||||||
del untrusted_payload
|
del untrusted_payload
|
||||||
|
|
||||||
volume = self.dest.volumes[self.arg]
|
volume = self.dest.volumes[self.arg]
|
||||||
snapshots = volume.revisions
|
snapshots = volume.revisions
|
||||||
assert untrusted_revision in snapshots
|
self.enforce(untrusted_revision in snapshots)
|
||||||
revision = untrusted_revision
|
revision = untrusted_revision
|
||||||
|
|
||||||
self.fire_event_for_permission(volume=volume, revision=revision)
|
self.fire_event_for_permission(volume=volume, revision=revision)
|
||||||
@ -391,7 +391,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', write=True)
|
scope='local', write=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_volume_clone_from(self):
|
def vm_volume_clone_from(self):
|
||||||
assert self.arg in self.dest.volumes.keys()
|
self.enforce(self.arg in self.dest.volumes.keys())
|
||||||
|
|
||||||
volume = self.dest.volumes[self.arg]
|
volume = self.dest.volumes[self.arg]
|
||||||
|
|
||||||
@ -403,7 +403,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
self.app.api_admin_pending_clone = {}
|
self.app.api_admin_pending_clone = {}
|
||||||
# don't handle collisions any better - if someone is so much out of
|
# don't handle collisions any better - if someone is so much out of
|
||||||
# luck, can try again anyway
|
# luck, can try again anyway
|
||||||
assert token not in self.app.api_admin_pending_clone
|
self.enforce(token not in self.app.api_admin_pending_clone)
|
||||||
|
|
||||||
self.app.api_admin_pending_clone[token] = volume
|
self.app.api_admin_pending_clone[token] = volume
|
||||||
return token
|
return token
|
||||||
@ -412,11 +412,11 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', write=True)
|
scope='local', write=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_volume_clone_to(self, untrusted_payload):
|
def vm_volume_clone_to(self, untrusted_payload):
|
||||||
assert self.arg in self.dest.volumes.keys()
|
self.enforce(self.arg in self.dest.volumes.keys())
|
||||||
untrusted_token = untrusted_payload.decode('ascii').strip()
|
untrusted_token = untrusted_payload.decode('ascii').strip()
|
||||||
del untrusted_payload
|
del untrusted_payload
|
||||||
assert untrusted_token in getattr(self.app,
|
self.enforce(
|
||||||
'api_admin_pending_clone', {})
|
untrusted_token in getattr(self.app, 'api_admin_pending_clone', {}))
|
||||||
token = untrusted_token
|
token = untrusted_token
|
||||||
del untrusted_token
|
del untrusted_token
|
||||||
|
|
||||||
@ -424,8 +424,8 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
del self.app.api_admin_pending_clone[token]
|
del self.app.api_admin_pending_clone[token]
|
||||||
|
|
||||||
# make sure the volume still exists, but invalidate token anyway
|
# make sure the volume still exists, but invalidate token anyway
|
||||||
assert str(src_volume.pool) in self.app.pools
|
self.enforce(str(src_volume.pool) in self.app.pools)
|
||||||
assert src_volume in self.app.pools[str(src_volume.pool)].volumes
|
self.enforce(src_volume in self.app.pools[str(src_volume.pool)].volumes)
|
||||||
|
|
||||||
dst_volume = self.dest.volumes[self.arg]
|
dst_volume = self.dest.volumes[self.arg]
|
||||||
|
|
||||||
@ -446,11 +446,11 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', write=True)
|
scope='local', write=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_volume_resize(self, untrusted_payload):
|
def vm_volume_resize(self, untrusted_payload):
|
||||||
assert self.arg in self.dest.volumes.keys()
|
self.enforce(self.arg in self.dest.volumes.keys())
|
||||||
untrusted_size = untrusted_payload.decode('ascii').strip()
|
untrusted_size = untrusted_payload.decode('ascii').strip()
|
||||||
del untrusted_payload
|
del untrusted_payload
|
||||||
assert untrusted_size.isdigit() # only digits, forbid '-' too
|
self.enforce(untrusted_size.isdigit()) # only digits, forbid '-' too
|
||||||
assert len(untrusted_size) <= 20 # limit to about 2^64
|
self.enforce(len(untrusted_size) <= 20) # limit to about 2^64
|
||||||
|
|
||||||
size = int(untrusted_size)
|
size = int(untrusted_size)
|
||||||
|
|
||||||
@ -472,7 +472,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
payload) and response from that call will be actually send to the
|
payload) and response from that call will be actually send to the
|
||||||
caller.
|
caller.
|
||||||
'''
|
'''
|
||||||
assert self.arg in self.dest.volumes.keys()
|
self.enforce(self.arg in self.dest.volumes.keys())
|
||||||
|
|
||||||
self.fire_event_for_permission()
|
self.fire_event_for_permission()
|
||||||
|
|
||||||
@ -480,7 +480,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
raise qubes.exc.QubesVMNotHaltedError(self.dest)
|
raise qubes.exc.QubesVMNotHaltedError(self.dest)
|
||||||
|
|
||||||
path = self.dest.storage.import_data(self.arg)
|
path = self.dest.storage.import_data(self.arg)
|
||||||
assert ' ' not in path
|
self.enforce(' ' not in path)
|
||||||
size = self.dest.volumes[self.arg].size
|
size = self.dest.volumes[self.arg].size
|
||||||
|
|
||||||
# when we know the action is allowed, inform extensions that it will
|
# when we know the action is allowed, inform extensions that it will
|
||||||
@ -493,13 +493,13 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', write=True)
|
scope='local', write=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_volume_set_revisions_to_keep(self, untrusted_payload):
|
def vm_volume_set_revisions_to_keep(self, untrusted_payload):
|
||||||
assert self.arg in self.dest.volumes.keys()
|
self.enforce(self.arg in self.dest.volumes.keys())
|
||||||
try:
|
try:
|
||||||
untrusted_value = int(untrusted_payload.decode('ascii'))
|
untrusted_value = int(untrusted_payload.decode('ascii'))
|
||||||
except (UnicodeDecodeError, ValueError):
|
except (UnicodeDecodeError, ValueError):
|
||||||
raise qubes.api.ProtocolError('Invalid value')
|
raise qubes.api.ProtocolError('Invalid value')
|
||||||
del untrusted_payload
|
del untrusted_payload
|
||||||
assert untrusted_value >= 0
|
self.enforce(untrusted_value >= 0)
|
||||||
newvalue = untrusted_value
|
newvalue = untrusted_value
|
||||||
del untrusted_value
|
del untrusted_value
|
||||||
|
|
||||||
@ -512,7 +512,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', write=True)
|
scope='local', write=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_volume_set_rw(self, untrusted_payload):
|
def vm_volume_set_rw(self, untrusted_payload):
|
||||||
assert self.arg in self.dest.volumes.keys()
|
self.enforce(self.arg in self.dest.volumes.keys())
|
||||||
try:
|
try:
|
||||||
newvalue = qubes.property.bool(None, None,
|
newvalue = qubes.property.bool(None, None,
|
||||||
untrusted_payload.decode('ascii'))
|
untrusted_payload.decode('ascii'))
|
||||||
@ -532,7 +532,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', read=True)
|
scope='local', read=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_tag_list(self):
|
def vm_tag_list(self):
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
|
|
||||||
tags = self.dest.tags
|
tags = self.dest.tags
|
||||||
|
|
||||||
@ -579,8 +579,8 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='global', read=True)
|
scope='global', read=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def pool_list(self):
|
def pool_list(self):
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
|
|
||||||
pools = self.fire_event_for_filter(self.app.pools)
|
pools = self.fire_event_for_filter(self.app.pools)
|
||||||
|
|
||||||
@ -590,8 +590,8 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='global', read=True)
|
scope='global', read=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def pool_listdrivers(self):
|
def pool_listdrivers(self):
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
|
|
||||||
drivers = self.fire_event_for_filter(qubes.storage.pool_drivers())
|
drivers = self.fire_event_for_filter(qubes.storage.pool_drivers())
|
||||||
|
|
||||||
@ -604,8 +604,8 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='global', read=True)
|
scope='global', read=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def pool_info(self):
|
def pool_info(self):
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
assert self.arg in self.app.pools.keys()
|
self.enforce(self.arg in self.app.pools.keys())
|
||||||
|
|
||||||
pool = self.app.pools[self.arg]
|
pool = self.app.pools[self.arg]
|
||||||
|
|
||||||
@ -635,30 +635,32 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='global', write=True)
|
scope='global', write=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def pool_add(self, untrusted_payload):
|
def pool_add(self, untrusted_payload):
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
drivers = qubes.storage.pool_drivers()
|
drivers = qubes.storage.pool_drivers()
|
||||||
assert self.arg in drivers
|
self.enforce(self.arg in drivers)
|
||||||
untrusted_pool_config = untrusted_payload.decode('ascii').splitlines()
|
untrusted_pool_config = untrusted_payload.decode('ascii').splitlines()
|
||||||
del untrusted_payload
|
del untrusted_payload
|
||||||
assert all(('=' in line) for line in untrusted_pool_config)
|
self.enforce(all(('=' in line) for line in untrusted_pool_config))
|
||||||
# pairs of (option, value)
|
# pairs of (option, value)
|
||||||
untrusted_pool_config = [line.split('=', 1)
|
untrusted_pool_config = [line.split('=', 1)
|
||||||
for line in untrusted_pool_config]
|
for line in untrusted_pool_config]
|
||||||
# reject duplicated options
|
# reject duplicated options
|
||||||
assert len(set(x[0] for x in untrusted_pool_config)) == \
|
self.enforce(
|
||||||
len([x[0] for x in untrusted_pool_config])
|
len(set(x[0] for x in untrusted_pool_config)) ==
|
||||||
|
len([x[0] for x in untrusted_pool_config]))
|
||||||
# and convert to dict
|
# and convert to dict
|
||||||
untrusted_pool_config = dict(untrusted_pool_config)
|
untrusted_pool_config = dict(untrusted_pool_config)
|
||||||
|
|
||||||
assert 'name' in untrusted_pool_config
|
self.enforce('name' in untrusted_pool_config)
|
||||||
untrusted_pool_name = untrusted_pool_config.pop('name')
|
untrusted_pool_name = untrusted_pool_config.pop('name')
|
||||||
allowed_chars = string.ascii_letters + string.digits + '-_.'
|
allowed_chars = string.ascii_letters + string.digits + '-_.'
|
||||||
assert all(c in allowed_chars for c in untrusted_pool_name)
|
self.enforce(all(c in allowed_chars for c in untrusted_pool_name))
|
||||||
pool_name = untrusted_pool_name
|
pool_name = untrusted_pool_name
|
||||||
assert pool_name not in self.app.pools
|
self.enforce(pool_name not in self.app.pools)
|
||||||
|
|
||||||
driver_parameters = qubes.storage.driver_parameters(self.arg)
|
driver_parameters = qubes.storage.driver_parameters(self.arg)
|
||||||
assert all(key in driver_parameters for key in untrusted_pool_config)
|
self.enforce(
|
||||||
|
all(key in driver_parameters for key in untrusted_pool_config))
|
||||||
pool_config = untrusted_pool_config
|
pool_config = untrusted_pool_config
|
||||||
|
|
||||||
self.fire_event_for_permission(name=pool_name,
|
self.fire_event_for_permission(name=pool_name,
|
||||||
@ -671,8 +673,8 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='global', write=True)
|
scope='global', write=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def pool_remove(self):
|
def pool_remove(self):
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
assert self.arg in self.app.pools.keys()
|
self.enforce(self.arg in self.app.pools.keys())
|
||||||
|
|
||||||
self.fire_event_for_permission()
|
self.fire_event_for_permission()
|
||||||
|
|
||||||
@ -683,15 +685,15 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='global', write=True)
|
scope='global', write=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def pool_set_revisions_to_keep(self, untrusted_payload):
|
def pool_set_revisions_to_keep(self, untrusted_payload):
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
assert self.arg in self.app.pools.keys()
|
self.enforce(self.arg in self.app.pools.keys())
|
||||||
pool = self.app.pools[self.arg]
|
pool = self.app.pools[self.arg]
|
||||||
try:
|
try:
|
||||||
untrusted_value = int(untrusted_payload.decode('ascii'))
|
untrusted_value = int(untrusted_payload.decode('ascii'))
|
||||||
except (UnicodeDecodeError, ValueError):
|
except (UnicodeDecodeError, ValueError):
|
||||||
raise qubes.api.ProtocolError('Invalid value')
|
raise qubes.api.ProtocolError('Invalid value')
|
||||||
del untrusted_payload
|
del untrusted_payload
|
||||||
assert untrusted_value >= 0
|
self.enforce(untrusted_value >= 0)
|
||||||
newvalue = untrusted_value
|
newvalue = untrusted_value
|
||||||
del untrusted_value
|
del untrusted_value
|
||||||
|
|
||||||
@ -704,8 +706,8 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='global', read=True)
|
scope='global', read=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def label_list(self):
|
def label_list(self):
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
|
|
||||||
labels = self.fire_event_for_filter(self.app.labels.values())
|
labels = self.fire_event_for_filter(self.app.labels.values())
|
||||||
|
|
||||||
@ -715,7 +717,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='global', read=True)
|
scope='global', read=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def label_get(self):
|
def label_get(self):
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
label = self.app.get_label(self.arg)
|
label = self.app.get_label(self.arg)
|
||||||
@ -730,7 +732,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='global', read=True)
|
scope='global', read=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def label_index(self):
|
def label_index(self):
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
label = self.app.get_label(self.arg)
|
label = self.app.get_label(self.arg)
|
||||||
@ -745,12 +747,12 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='global', write=True)
|
scope='global', write=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def label_create(self, untrusted_payload):
|
def label_create(self, untrusted_payload):
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
|
|
||||||
# don't confuse label name with label index
|
# don't confuse label name with label index
|
||||||
assert not self.arg.isdigit()
|
self.enforce(not self.arg.isdigit())
|
||||||
allowed_chars = string.ascii_letters + string.digits + '-_.'
|
allowed_chars = string.ascii_letters + string.digits + '-_.'
|
||||||
assert all(c in allowed_chars for c in self.arg)
|
self.enforce(all(c in allowed_chars for c in self.arg))
|
||||||
try:
|
try:
|
||||||
self.app.get_label(self.arg)
|
self.app.get_label(self.arg)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -760,10 +762,10 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
raise qubes.exc.QubesValueError('label already exists')
|
raise qubes.exc.QubesValueError('label already exists')
|
||||||
|
|
||||||
untrusted_payload = untrusted_payload.decode('ascii').strip()
|
untrusted_payload = untrusted_payload.decode('ascii').strip()
|
||||||
assert len(untrusted_payload) == 8
|
self.enforce(len(untrusted_payload) == 8)
|
||||||
assert untrusted_payload.startswith('0x')
|
self.enforce(untrusted_payload.startswith('0x'))
|
||||||
# besides prefix, only hex digits are allowed
|
# besides prefix, only hex digits are allowed
|
||||||
assert all(x in string.hexdigits for x in untrusted_payload[2:])
|
self.enforce(all(x in string.hexdigits for x in untrusted_payload[2:]))
|
||||||
|
|
||||||
# SEE: #2732
|
# SEE: #2732
|
||||||
color = untrusted_payload
|
color = untrusted_payload
|
||||||
@ -782,14 +784,14 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='global', write=True)
|
scope='global', write=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def label_remove(self):
|
def label_remove(self):
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
label = self.app.get_label(self.arg)
|
label = self.app.get_label(self.arg)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise qubes.exc.QubesValueError
|
raise qubes.exc.QubesValueError
|
||||||
# don't allow removing default labels
|
# don't allow removing default labels
|
||||||
assert label.index > qubes.config.max_default_label
|
self.enforce(label.index > qubes.config.max_default_label)
|
||||||
|
|
||||||
# FIXME: this should be in app.add_label()
|
# FIXME: this should be in app.add_label()
|
||||||
for vm in self.app.domains:
|
for vm in self.app.domains:
|
||||||
@ -805,7 +807,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', execute=True)
|
scope='local', execute=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_start(self):
|
def vm_start(self):
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
self.fire_event_for_permission()
|
self.fire_event_for_permission()
|
||||||
try:
|
try:
|
||||||
yield from self.dest.start()
|
yield from self.dest.start()
|
||||||
@ -819,7 +821,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', execute=True)
|
scope='local', execute=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_shutdown(self):
|
def vm_shutdown(self):
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
self.fire_event_for_permission()
|
self.fire_event_for_permission()
|
||||||
yield from self.dest.shutdown()
|
yield from self.dest.shutdown()
|
||||||
|
|
||||||
@ -827,7 +829,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', execute=True)
|
scope='local', execute=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_pause(self):
|
def vm_pause(self):
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
self.fire_event_for_permission()
|
self.fire_event_for_permission()
|
||||||
yield from self.dest.pause()
|
yield from self.dest.pause()
|
||||||
|
|
||||||
@ -835,7 +837,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', execute=True)
|
scope='local', execute=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_unpause(self):
|
def vm_unpause(self):
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
self.fire_event_for_permission()
|
self.fire_event_for_permission()
|
||||||
yield from self.dest.unpause()
|
yield from self.dest.unpause()
|
||||||
|
|
||||||
@ -843,7 +845,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', execute=True)
|
scope='local', execute=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_kill(self):
|
def vm_kill(self):
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
self.fire_event_for_permission()
|
self.fire_event_for_permission()
|
||||||
yield from self.dest.kill()
|
yield from self.dest.kill()
|
||||||
|
|
||||||
@ -851,7 +853,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='global', read=True)
|
scope='global', read=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def events(self):
|
def events(self):
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
|
|
||||||
# run until client connection is terminated
|
# run until client connection is terminated
|
||||||
self.cancellable = True
|
self.cancellable = True
|
||||||
@ -893,7 +895,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', read=True)
|
scope='local', read=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_feature_list(self):
|
def vm_feature_list(self):
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
features = self.fire_event_for_filter(self.dest.features.keys())
|
features = self.fire_event_for_filter(self.dest.features.keys())
|
||||||
return ''.join('{}\n'.format(feature) for feature in features)
|
return ''.join('{}\n'.format(feature) for feature in features)
|
||||||
|
|
||||||
@ -978,7 +980,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
untrusted_payload=untrusted_payload)
|
untrusted_payload=untrusted_payload)
|
||||||
|
|
||||||
def _vm_create(self, vm_type, allow_pool=False, untrusted_payload=None):
|
def _vm_create(self, vm_type, allow_pool=False, untrusted_payload=None):
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
|
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
pool = None
|
pool = None
|
||||||
@ -992,10 +994,10 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
# when given VM class do need a template
|
# when given VM class do need a template
|
||||||
if hasattr(vm_class, 'template'):
|
if hasattr(vm_class, 'template'):
|
||||||
if self.arg:
|
if self.arg:
|
||||||
assert self.arg in self.app.domains
|
self.enforce(self.arg in self.app.domains)
|
||||||
kwargs['template'] = self.app.domains[self.arg]
|
kwargs['template'] = self.app.domains[self.arg]
|
||||||
else:
|
else:
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
|
|
||||||
for untrusted_param in untrusted_payload.decode('ascii',
|
for untrusted_param in untrusted_payload.decode('ascii',
|
||||||
errors='strict').split(' '):
|
errors='strict').split(' '):
|
||||||
@ -1009,9 +1011,9 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
|
|
||||||
elif untrusted_key == 'label':
|
elif untrusted_key == 'label':
|
||||||
# don't confuse label name with label index
|
# don't confuse label name with label index
|
||||||
assert not untrusted_value.isdigit()
|
self.enforce(not untrusted_value.isdigit())
|
||||||
allowed_chars = string.ascii_letters + string.digits + '-_.'
|
allowed_chars = string.ascii_letters + string.digits + '-_.'
|
||||||
assert all(c in allowed_chars for c in untrusted_value)
|
self.enforce(all(c in allowed_chars for c in untrusted_value))
|
||||||
try:
|
try:
|
||||||
kwargs['label'] = self.app.get_label(untrusted_value)
|
kwargs['label'] = self.app.get_label(untrusted_value)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -1025,8 +1027,8 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
untrusted_volume = untrusted_key.split(':', 1)[1]
|
untrusted_volume = untrusted_key.split(':', 1)[1]
|
||||||
# kind of ugly, but actual list of volumes is available only
|
# kind of ugly, but actual list of volumes is available only
|
||||||
# after creating a VM
|
# after creating a VM
|
||||||
assert untrusted_volume in ['root', 'private', 'volatile',
|
self.enforce(untrusted_volume in [
|
||||||
'kernel']
|
'root', 'private', 'volatile', 'kernel'])
|
||||||
volume = untrusted_volume
|
volume = untrusted_volume
|
||||||
if volume in pools:
|
if volume in pools:
|
||||||
raise qubes.api.ProtocolError(
|
raise qubes.api.ProtocolError(
|
||||||
@ -1065,7 +1067,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='global', write=True)
|
scope='global', write=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def create_disposable(self):
|
def create_disposable(self):
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
|
|
||||||
if self.dest.name == 'dom0':
|
if self.dest.name == 'dom0':
|
||||||
dispvm_template = self.src.default_dispvm
|
dispvm_template = self.src.default_dispvm
|
||||||
@ -1084,7 +1086,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='global', write=True)
|
scope='global', write=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_remove(self):
|
def vm_remove(self):
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
|
|
||||||
self.fire_event_for_permission()
|
self.fire_event_for_permission()
|
||||||
|
|
||||||
@ -1116,7 +1118,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
devices = [dev for dev in devices if dev.ident == self.arg]
|
devices = [dev for dev in devices if dev.ident == self.arg]
|
||||||
# no duplicated devices, but device may not exists, in which case
|
# no duplicated devices, but device may not exists, in which case
|
||||||
# the list is empty
|
# the list is empty
|
||||||
assert len(devices) <= 1
|
self.enforce(len(devices) <= 1)
|
||||||
devices = self.fire_event_for_filter(devices, devclass=devclass)
|
devices = self.fire_event_for_filter(devices, devclass=devclass)
|
||||||
|
|
||||||
dev_info = {}
|
dev_info = {}
|
||||||
@ -1133,7 +1135,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
# specification
|
# specification
|
||||||
(('description', dev.description),)
|
(('description', dev.description),)
|
||||||
))
|
))
|
||||||
assert '\n' not in properties_txt
|
self.enforce('\n' not in properties_txt)
|
||||||
dev_info[dev.ident] = properties_txt
|
dev_info[dev.ident] = properties_txt
|
||||||
|
|
||||||
return ''.join('{} {}\n'.format(ident, dev_info[ident])
|
return ''.join('{} {}\n'.format(ident, dev_info[ident])
|
||||||
@ -1154,7 +1156,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
== (select_backend, select_ident)]
|
== (select_backend, select_ident)]
|
||||||
# no duplicated devices, but device may not exists, in which case
|
# no duplicated devices, but device may not exists, in which case
|
||||||
# the list is empty
|
# the list is empty
|
||||||
assert len(device_assignments) <= 1
|
self.enforce(len(device_assignments) <= 1)
|
||||||
device_assignments = self.fire_event_for_filter(device_assignments,
|
device_assignments = self.fire_event_for_filter(device_assignments,
|
||||||
devclass=devclass)
|
devclass=devclass)
|
||||||
|
|
||||||
@ -1166,7 +1168,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
dev.options.items(),
|
dev.options.items(),
|
||||||
(('persistent', 'yes' if dev.persistent else 'no'),)
|
(('persistent', 'yes' if dev.persistent else 'no'),)
|
||||||
))
|
))
|
||||||
assert '\n' not in properties_txt
|
self.enforce('\n' not in properties_txt)
|
||||||
ident = '{!s}+{!s}'.format(dev.backend_domain, dev.ident)
|
ident = '{!s}+{!s}'.format(dev.backend_domain, dev.ident)
|
||||||
dev_info[ident] = properties_txt
|
dev_info[ident] = properties_txt
|
||||||
|
|
||||||
@ -1254,7 +1256,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
def vm_device_set_persistent(self, endpoint, untrusted_payload):
|
def vm_device_set_persistent(self, endpoint, untrusted_payload):
|
||||||
devclass = endpoint
|
devclass = endpoint
|
||||||
|
|
||||||
assert untrusted_payload in (b'True', b'False')
|
self.enforce(untrusted_payload in (b'True', b'False'))
|
||||||
persistent = untrusted_payload == b'True'
|
persistent = untrusted_payload == b'True'
|
||||||
del untrusted_payload
|
del untrusted_payload
|
||||||
|
|
||||||
@ -1264,7 +1266,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
matching_devices = [dev for dev
|
matching_devices = [dev for dev
|
||||||
in self.dest.devices[devclass].attached()
|
in self.dest.devices[devclass].attached()
|
||||||
if dev.backend_domain.name == backend_domain and dev.ident == ident]
|
if dev.backend_domain.name == backend_domain and dev.ident == ident]
|
||||||
assert len(matching_devices) == 1
|
self.enforce(len(matching_devices) == 1)
|
||||||
dev = matching_devices[0]
|
dev = matching_devices[0]
|
||||||
|
|
||||||
self.fire_event_for_permission(device=dev,
|
self.fire_event_for_permission(device=dev,
|
||||||
@ -1277,7 +1279,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', read=True)
|
scope='local', read=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_firewall_get(self):
|
def vm_firewall_get(self):
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
|
|
||||||
self.fire_event_for_permission()
|
self.fire_event_for_permission()
|
||||||
|
|
||||||
@ -1289,7 +1291,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', write=True)
|
scope='local', write=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_firewall_set(self, untrusted_payload):
|
def vm_firewall_set(self, untrusted_payload):
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
rules = []
|
rules = []
|
||||||
for untrusted_line in untrusted_payload.decode('ascii',
|
for untrusted_line in untrusted_payload.decode('ascii',
|
||||||
errors='strict').splitlines():
|
errors='strict').splitlines():
|
||||||
@ -1306,7 +1308,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', execute=True)
|
scope='local', execute=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_firewall_reload(self):
|
def vm_firewall_reload(self):
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
|
|
||||||
self.fire_event_for_permission()
|
self.fire_event_for_permission()
|
||||||
|
|
||||||
@ -1367,7 +1369,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
'qubes.BackupPassphrase+' + self.arg)
|
'qubes.BackupPassphrase+' + self.arg)
|
||||||
# make it foolproof against "echo passphrase" implementation
|
# make it foolproof against "echo passphrase" implementation
|
||||||
passphrase = passphrase.strip()
|
passphrase = passphrase.strip()
|
||||||
assert b'\n' not in passphrase
|
self.enforce(b'\n' not in passphrase)
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
raise qubes.exc.QubesException(
|
raise qubes.exc.QubesException(
|
||||||
'Failed to retrieve passphrase from \'{}\' VM'.format(
|
'Failed to retrieve passphrase from \'{}\' VM'.format(
|
||||||
@ -1410,9 +1412,9 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='global', read=True, execute=True)
|
scope='global', read=True, execute=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def backup_execute(self):
|
def backup_execute(self):
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
assert self.arg
|
self.enforce(self.arg)
|
||||||
assert '/' not in self.arg
|
self.enforce('/' not in self.arg)
|
||||||
|
|
||||||
self.fire_event_for_permission()
|
self.fire_event_for_permission()
|
||||||
|
|
||||||
@ -1430,7 +1432,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
self._backup_progress_callback, self.arg)
|
self._backup_progress_callback, self.arg)
|
||||||
|
|
||||||
# forbid running the same backup operation twice at the time
|
# forbid running the same backup operation twice at the time
|
||||||
assert self.arg not in self.app.api_admin_running_backups
|
self.enforce(self.arg not in self.app.api_admin_running_backups)
|
||||||
|
|
||||||
backup_task = asyncio.ensure_future(backup.backup_do())
|
backup_task = asyncio.ensure_future(backup.backup_do())
|
||||||
self.app.api_admin_running_backups[self.arg] = backup_task
|
self.app.api_admin_running_backups[self.arg] = backup_task
|
||||||
@ -1445,9 +1447,9 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='global', execute=True)
|
scope='global', execute=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def backup_cancel(self):
|
def backup_cancel(self):
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
assert self.arg
|
self.enforce(self.arg)
|
||||||
assert '/' not in self.arg
|
self.enforce('/' not in self.arg)
|
||||||
|
|
||||||
self.fire_event_for_permission()
|
self.fire_event_for_permission()
|
||||||
|
|
||||||
@ -1463,9 +1465,9 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='local', read=True)
|
scope='local', read=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def backup_info(self):
|
def backup_info(self):
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
assert self.arg
|
self.enforce(self.arg)
|
||||||
assert '/' not in self.arg
|
self.enforce('/' not in self.arg)
|
||||||
|
|
||||||
self.fire_event_for_permission()
|
self.fire_event_for_permission()
|
||||||
|
|
||||||
@ -1527,7 +1529,7 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
scope='global', read=True)
|
scope='global', read=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def vm_stats(self):
|
def vm_stats(self):
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
|
|
||||||
# run until client connection is terminated
|
# run until client connection is terminated
|
||||||
self.cancellable = True
|
self.cancellable = True
|
||||||
|
@ -39,8 +39,8 @@ class QubesInternalAPI(qubes.api.AbstractQubesAPI):
|
|||||||
@qubes.api.method('internal.GetSystemInfo', no_payload=True)
|
@qubes.api.method('internal.GetSystemInfo', no_payload=True)
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def getsysteminfo(self):
|
def getsysteminfo(self):
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
|
|
||||||
system_info = {'domains': {
|
system_info = {'domains': {
|
||||||
domain.name: {
|
domain.name: {
|
||||||
@ -64,7 +64,7 @@ class QubesInternalAPI(qubes.api.AbstractQubesAPI):
|
|||||||
when actual import is finished. Response from this method is sent do
|
when actual import is finished. Response from this method is sent do
|
||||||
the client (as a response for admin.vm.volume.Import call).
|
the client (as a response for admin.vm.volume.Import call).
|
||||||
'''
|
'''
|
||||||
assert self.arg in self.dest.volumes.keys()
|
self.enforce(self.arg in self.dest.volumes.keys())
|
||||||
success = untrusted_payload == b'ok'
|
success = untrusted_payload == b'ok'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -46,8 +46,8 @@ class QubesMiscAPI(qubes.api.AbstractQubesAPI):
|
|||||||
appropriate extensions. Requests not explicitly handled by some
|
appropriate extensions. Requests not explicitly handled by some
|
||||||
extension are ignored.
|
extension are ignored.
|
||||||
'''
|
'''
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
|
|
||||||
prefix = '/features-request/'
|
prefix = '/features-request/'
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ class QubesMiscAPI(qubes.api.AbstractQubesAPI):
|
|||||||
safe_set = string.ascii_letters + string.digits
|
safe_set = string.ascii_letters + string.digits
|
||||||
for untrusted_key in untrusted_features:
|
for untrusted_key in untrusted_features:
|
||||||
untrusted_value = untrusted_features[untrusted_key]
|
untrusted_value = untrusted_features[untrusted_key]
|
||||||
assert all((c in safe_set) for c in untrusted_value)
|
self.enforce(all((c in safe_set) for c in untrusted_value))
|
||||||
|
|
||||||
yield from self.src.fire_event_async('features-request',
|
yield from self.src.fire_event_async('features-request',
|
||||||
untrusted_features=untrusted_features)
|
untrusted_features=untrusted_features)
|
||||||
@ -71,8 +71,8 @@ class QubesMiscAPI(qubes.api.AbstractQubesAPI):
|
|||||||
'''
|
'''
|
||||||
Legacy version of qubes.FeaturesRequest, used by Qubes Windows Tools
|
Legacy version of qubes.FeaturesRequest, used by Qubes Windows Tools
|
||||||
'''
|
'''
|
||||||
assert self.dest.name == 'dom0'
|
self.enforce(self.dest.name == 'dom0')
|
||||||
assert not self.arg
|
self.enforce(not self.arg)
|
||||||
|
|
||||||
untrusted_features = {}
|
untrusted_features = {}
|
||||||
safe_set = string.ascii_letters + string.digits
|
safe_set = string.ascii_letters + string.digits
|
||||||
@ -83,7 +83,7 @@ class QubesMiscAPI(qubes.api.AbstractQubesAPI):
|
|||||||
if untrusted_value:
|
if untrusted_value:
|
||||||
untrusted_value = untrusted_value.decode('ascii',
|
untrusted_value = untrusted_value.decode('ascii',
|
||||||
errors='strict')
|
errors='strict')
|
||||||
assert all((c in safe_set) for c in untrusted_value)
|
self.enforce(all((c in safe_set) for c in untrusted_value))
|
||||||
untrusted_features[feature] = untrusted_value
|
untrusted_features[feature] = untrusted_value
|
||||||
del untrusted_value
|
del untrusted_value
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ class QubesMiscAPI(qubes.api.AbstractQubesAPI):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
untrusted_update_count = untrusted_payload.strip()
|
untrusted_update_count = untrusted_payload.strip()
|
||||||
assert untrusted_update_count.isdigit()
|
self.enforce(untrusted_update_count.isdigit())
|
||||||
# now sanitized
|
# now sanitized
|
||||||
update_count = int(untrusted_update_count)
|
update_count = int(untrusted_update_count)
|
||||||
del untrusted_update_count
|
del untrusted_update_count
|
||||||
|
@ -20,26 +20,27 @@
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import itertools
|
|
||||||
import logging
|
|
||||||
import functools
|
|
||||||
import string
|
|
||||||
import termios
|
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import datetime
|
||||||
from qubes.utils import size_to_human
|
|
||||||
import stat
|
|
||||||
import os
|
|
||||||
import fcntl
|
import fcntl
|
||||||
import subprocess
|
import functools
|
||||||
|
import grp
|
||||||
|
import itertools
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
import pwd
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
|
import stat
|
||||||
|
import string
|
||||||
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import termios
|
||||||
import time
|
import time
|
||||||
import grp
|
|
||||||
import pwd
|
from .utils import size_to_human
|
||||||
import datetime
|
|
||||||
import qubes
|
import qubes
|
||||||
import qubes.core2migration
|
import qubes.core2migration
|
||||||
import qubes.storage
|
import qubes.storage
|
||||||
@ -257,17 +258,14 @@ class Backup(object):
|
|||||||
size = qubes.storage.file.get_disk_usage(file_path)
|
size = qubes.storage.file.get_disk_usage(file_path)
|
||||||
|
|
||||||
if subdir is None:
|
if subdir is None:
|
||||||
abs_file_path = os.path.abspath(file_path)
|
abs_file_dir = pathlib.Path(file_path).resolve().parent
|
||||||
abs_base_dir = os.path.abspath(
|
abs_base_dir = pathlib.Path(
|
||||||
qubes.config.system_path["qubes_base_dir"]) + '/'
|
qubes.config.system_path["qubes_base_dir"]).resolve()
|
||||||
abs_file_dir = os.path.dirname(abs_file_path) + '/'
|
# this raises ValueError if abs_file_dir is not in abs_base_dir
|
||||||
(nothing, directory, subdir) = \
|
subdir = str(abs_file_dir.relative_to(abs_base_dir))
|
||||||
abs_file_dir.partition(abs_base_dir)
|
|
||||||
assert nothing == ""
|
if not subdir.endswith(os.path.sep):
|
||||||
assert directory == abs_base_dir
|
subdir += os.path.sep
|
||||||
else:
|
|
||||||
if subdir and not subdir.endswith('/'):
|
|
||||||
subdir += '/'
|
|
||||||
|
|
||||||
#: real path to the file
|
#: real path to the file
|
||||||
self.path = file_path
|
self.path = file_path
|
||||||
|
@ -238,9 +238,9 @@ class DeviceCollection(object):
|
|||||||
|
|
||||||
if device_assignment.bus is None:
|
if device_assignment.bus is None:
|
||||||
device_assignment.bus = self._bus
|
device_assignment.bus = self._bus
|
||||||
else:
|
elif device_assignment.bus != self._bus:
|
||||||
assert device_assignment.bus == self._bus, \
|
raise ValueError(
|
||||||
"Trying to attach DeviceAssignment of a different device class"
|
'Trying to attach DeviceAssignment of a different device class')
|
||||||
|
|
||||||
if not device_assignment.persistent and self._vm.is_halted():
|
if not device_assignment.persistent and self._vm.is_halted():
|
||||||
raise qubes.exc.QubesVMNotRunningError(self._vm,
|
raise qubes.exc.QubesVMNotRunningError(self._vm,
|
||||||
|
@ -39,9 +39,10 @@ class RuleOption(object):
|
|||||||
# subset of string.punctuation
|
# subset of string.punctuation
|
||||||
safe_set = string.ascii_letters + string.digits + \
|
safe_set = string.ascii_letters + string.digits + \
|
||||||
':;,./-_[]'
|
':;,./-_[]'
|
||||||
assert all(x in safe_set for x in str(untrusted_value))
|
untrusted_value = str(untrusted_value)
|
||||||
value = str(untrusted_value)
|
if not all(x in safe_set for x in untrusted_value):
|
||||||
self._value = value
|
raise ValueError('strange characters in rule')
|
||||||
|
self._value = untrusted_value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def rule(self):
|
def rule(self):
|
||||||
@ -226,9 +227,10 @@ class Comment(RuleOption):
|
|||||||
# subset of string.punctuation
|
# subset of string.punctuation
|
||||||
safe_set = string.ascii_letters + string.digits + \
|
safe_set = string.ascii_letters + string.digits + \
|
||||||
':;,./-_[] '
|
':;,./-_[] '
|
||||||
assert all(x in safe_set for x in str(untrusted_value))
|
untrusted_value = str(untrusted_value)
|
||||||
value = str(untrusted_value)
|
if not all(x in safe_set for x in untrusted_value):
|
||||||
self._value = value
|
raise ValueError('strange characters comment')
|
||||||
|
self._value = untrusted_value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def rule(self):
|
def rule(self):
|
||||||
|
@ -280,7 +280,8 @@ class Tags(set):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def validate_tag(tag):
|
def validate_tag(tag):
|
||||||
safe_set = string.ascii_letters + string.digits + '-_'
|
safe_set = string.ascii_letters + string.digits + '-_'
|
||||||
assert all((x in safe_set) for x in tag)
|
if not all((x in safe_set) for x in tag):
|
||||||
|
raise ValueError('disallowed characters')
|
||||||
|
|
||||||
|
|
||||||
class BaseVM(qubes.PropertyHolder):
|
class BaseVM(qubes.PropertyHolder):
|
||||||
|
@ -302,7 +302,9 @@ class NetVMMixin(qubes.events.Emitter):
|
|||||||
|
|
||||||
if not self.is_running():
|
if not self.is_running():
|
||||||
raise qubes.exc.QubesVMNotRunningError(self)
|
raise qubes.exc.QubesVMNotRunningError(self)
|
||||||
assert self.netvm is not None
|
if self.netvm is None:
|
||||||
|
raise qubes.exc.QubesVMError(self,
|
||||||
|
'netvm should not be {}'.format(self.netvm))
|
||||||
|
|
||||||
if not self.netvm.is_running(): # pylint: disable=no-member
|
if not self.netvm.is_running(): # pylint: disable=no-member
|
||||||
# pylint: disable=no-member
|
# pylint: disable=no-member
|
||||||
@ -319,7 +321,9 @@ class NetVMMixin(qubes.events.Emitter):
|
|||||||
|
|
||||||
if not self.is_running():
|
if not self.is_running():
|
||||||
raise qubes.exc.QubesVMNotRunningError(self)
|
raise qubes.exc.QubesVMNotRunningError(self)
|
||||||
assert self.netvm is not None
|
if self.netvm is None:
|
||||||
|
raise qubes.exc.QubesVMError(self,
|
||||||
|
'netvm should not be {}'.format(self.netvm))
|
||||||
|
|
||||||
self.libvirt_domain.detachDevice(
|
self.libvirt_domain.detachDevice(
|
||||||
self.app.env.get_template('libvirt/devices/net.xml').render(
|
self.app.env.get_template('libvirt/devices/net.xml').render(
|
||||||
|
@ -416,10 +416,13 @@ class PolicyAction(object):
|
|||||||
raise AccessDenied(
|
raise AccessDenied(
|
||||||
'denied by policy {}:{}'.format(rule.filename, rule.lineno))
|
'denied by policy {}:{}'.format(rule.filename, rule.lineno))
|
||||||
elif rule.action == Action.ask:
|
elif rule.action == Action.ask:
|
||||||
assert targets_for_ask is not None
|
if targets_for_ask is None:
|
||||||
|
raise AccessDenied(
|
||||||
|
'invalid policy {}:{}'.format(rule.filename, rule.lineno))
|
||||||
elif rule.action == Action.allow:
|
elif rule.action == Action.allow:
|
||||||
assert targets_for_ask is None
|
if targets_for_ask is not None or target is None:
|
||||||
assert target is not None
|
raise AccessDenied(
|
||||||
|
'invalid policy {}:{}'.format(rule.filename, rule.lineno))
|
||||||
self.action = rule.action
|
self.action = rule.action
|
||||||
|
|
||||||
def handle_user_response(self, response, target=None):
|
def handle_user_response(self, response, target=None):
|
||||||
|
Loading…
Reference in New Issue
Block a user