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