74
if 'uses' in self.snap_yaml:
76
# TODO: need to adjust for native security skills
77
for slot in self.snap_yaml['uses']:
78
if 'type' not in self.snap_yaml['uses'][slot] or \
79
self.snap_yaml['uses'][slot]['type'] != \
74
if 'slots' in self.snap_yaml:
76
# TODO: need to adjust for native security interfaces
77
for slot in self.snap_yaml['slots']:
78
if 'interface' not in self.snap_yaml['slots'][slot] or \
79
self.snap_yaml['slots'][slot]['interface'] != \
82
for k in self.skill_types['migration-skill']:
83
if k in self.snap_yaml['uses'][slot]:
82
for k in self.interfaces['old-security']:
83
if k in self.snap_yaml['slots'][slot]:
84
84
# This check means we don't have to verify in the
86
if not isinstance(self.snap_yaml['uses'][slot][k],
87
type(self.skill_types['migration-skill'][k])):
88
error("Invalid yaml for uses/%s/%s" % (slot, k)) # pragma: nocover
89
if slot not in sec['uses']:
90
sec['uses'][slot] = {}
91
sec['uses'][slot][k] = self.snap_yaml['uses'][slot][k]
86
if not isinstance(self.snap_yaml['slots'][slot][k],
87
type(self.interfaces['old-security'][k])):
88
error("Invalid yaml for slots/%s/%s" % (slot, k)) # pragma: nocover
89
if slot not in sec['slots']:
90
sec['slots'][slot] = {}
91
sec['slots'][slot][k] = self.snap_yaml['slots'][slot][k]
93
93
if 'apps' in self.snap_yaml:
95
95
for app in self.snap_yaml['apps']:
96
if 'uses' not in self.snap_yaml['apps'][app]:
96
if 'slots' not in self.snap_yaml['apps'][app]:
98
98
# This check means we don't have to verify in the individual
100
elif not isinstance(self.snap_yaml['apps'][app]['uses'], list):
101
error("Invalid yaml for %s/uses" % app) # pragma: nocover
100
elif not isinstance(self.snap_yaml['apps'][app]['slots'], list):
101
error("Invalid yaml for %s/slots" % app) # pragma: nocover
102
102
if app not in sec['apps']:
103
103
sec['apps'][app] = {}
104
sec['apps'][app]['uses'] = self.snap_yaml['apps'][app]['uses']
104
sec['apps'][app]['slots'] = self.snap_yaml['apps'][app]['slots']
108
108
def _extract_security_profile(self, slot, key):
109
109
'''Extract security profile'''
110
rel_fn = self.policies['uses'][slot]['security-policy'][key]
110
rel_fn = self.policies['slots'][slot]['security-policy'][key]
112
112
fn = os.path.join(self.unpack_dir, rel_fn)
113
113
if not os.path.exists(fn):
125
125
'''Get 'security-policy' policies'''
126
126
raw_profiles = {}
128
if 'uses' not in self.policies:
128
if 'slots' not in self.policies:
129
129
return raw_profiles
131
for slot in self.policies['uses']:
132
if 'security-policy' not in self.policies['uses'][slot]:
131
for slot in self.policies['slots']:
132
if 'security-policy' not in self.policies['slots'][slot]:
135
135
if slot not in raw_profiles:
136
136
raw_profiles[slot] = {}
138
138
for k in ['apparmor', 'seccomp']:
139
if k in self.policies['uses'][slot]['security-policy']:
139
if k in self.policies['slots'][slot]['security-policy']:
140
140
raw_profiles[slot][k] = \
141
141
self._extract_security_profile(slot, k)
184
184
# frameworks may reference their own caps
185
185
frameworks.append(self.snap_yaml['name'])
187
for slot in self.policies['uses']:
188
if 'caps' not in self.policies['uses'][slot]:
187
for slot in self.policies['slots']:
188
if 'caps' not in self.policies['slots'][slot]:
192
for cap in self.policies['uses'][slot]['caps']:
192
for cap in self.policies['slots'][slot]['caps']:
193
193
# TODO: this will go away when frameworks are gone
194
194
framework_cap = False
195
195
for f in frameworks:
248
248
'syscalls': re.compile(VALID_SYSCALL),
251
for slot in self.policies['uses']:
251
for slot in self.policies['slots']:
252
252
key = 'security-override'
253
if key not in self.policies['uses'][slot]:
253
if key not in self.policies['slots'][slot]:
257
257
n = self._get_check_name(key, extra=slot)
259
if len(self.policies['uses'][slot][key].keys()) == 0:
259
if len(self.policies['slots'][slot][key].keys()) == 0:
261
261
s = "nothing specified in '%s' for '%s'" % (key, slot)
263
for f in self.policies['uses'][slot][key].keys():
263
for f in self.policies['slots'][slot][key].keys():
264
264
if f not in allowed_fields:
266
266
s = "unknown field '%s' in " % f + \
267
267
"'%s' for '%s'" % (key, slot)
268
elif not isinstance(self.policies['uses'][slot][key][f],
268
elif not isinstance(self.policies['slots'][slot][key][f],
271
271
s = "invalid %s entry: %s (not a list)" % \
272
(f, self.policies['uses'][slot][key][f])
272
(f, self.policies['slots'][slot][key][f])
275
for v in self.policies['uses'][slot][key][f]:
275
for v in self.policies['slots'][slot][key][f]:
276
276
if not allowed_fields[f].search(v):
278
278
if len(errors) > 0:
296
296
sc_skip_pat = re.compile(r'^(\s*#|\s*$)')
297
297
sc_valid_pat = re.compile(VALID_SYSCALL)
299
for slot in self.policies['uses']:
299
for slot in self.policies['slots']:
300
300
key = 'security-policy'
301
if key not in self.policies['uses'][slot]:
301
if key not in self.policies['slots'][slot]:
305
305
n = self._get_check_name(key, extra=slot)
307
for f in self.policies['uses'][slot][key].keys():
307
for f in self.policies['slots'][slot][key].keys():
308
308
if f not in allowed_fields:
310
310
s = "unknown field '%s' in " % f + \
311
311
"'%s' for '%s'" % (key, slot)
312
elif not isinstance(self.policies['uses'][slot][key][f],
312
elif not isinstance(self.policies['slots'][slot][key][f],
315
315
s = "invalid %s entry: %s (not a str)" % \
316
(f, self.policies['uses'][slot][key][f])
316
(f, self.policies['slots'][slot][key][f])
317
317
self._add_result(t, n, s)
319
319
for slot in self.raw_profiles:
385
385
# frameworks may reference their own caps
386
386
frameworks.append(self.snap_yaml['name'])
388
for slot in self.policies['uses']:
389
if 'security-template' not in self.policies['uses'][slot]:
388
for slot in self.policies['slots']:
389
if 'security-template' not in self.policies['slots'][slot]:
392
template = self.policies['uses'][slot]['security-template']
392
template = self.policies['slots'][slot]['security-template']
394
394
# TODO: this will go away when frameworks are gone
395
395
framework_template = False
429
429
self._add_result(t, n, s, manual_review=m)
431
431
def check_security_combinations(self):
432
'''Verify security yaml uses valid combinations'''
433
if not self.is_snap2 or 'uses' not in self.policies:
432
'''Verify security yaml slots valid combinations'''
433
if not self.is_snap2 or 'slots' not in self.policies:
436
for slot in self.policies['uses']:
436
for slot in self.policies['slots']:
438
438
n = self._get_check_name('yaml_combinations', extra=slot)
440
if "security-policy" in self.policies['uses'][slot]:
440
if "security-policy" in self.policies['slots'][slot]:
441
441
for i in ['security-override', 'security-template', 'caps']:
442
if i in self.policies['uses'][slot]:
443
tmp = list(self.policies['uses'][slot].keys())
442
if i in self.policies['slots'][slot]:
443
tmp = list(self.policies['slots'][slot].keys())
444
444
tmp.remove("security-policy")
446
446
s = "found '%s' with 'security-policy'" % \
457
457
n = self._get_check_name('yaml_combinations_apps', app=app)
460
for slot_ref in self.policies['apps'][app]['uses']:
461
if slot_ref not in self.policies['uses']:
460
for slot_ref in self.policies['apps'][app]['slots']:
461
if slot_ref not in self.policies['slots']:
464
464
for i in ['security-override', 'security-template', 'caps',
465
465
'security-policy']:
466
if i in self.policies['uses'][slot_ref] and \
466
if i in self.policies['slots'][slot_ref] and \
467
467
i not in has_decl:
468
468
has_decl.append(i)
472
472
if i in has_decl:
473
473
has_decl.remove("security-policy")
475
s = "'%s' uses 'security-policy' with '%s'" % (
475
s = "'%s' slots 'security-policy' with '%s'" % (
476
476
app, ",".join(sorted(has_decl)))
478
478
self._add_result(t, n, s)
480
def check_uses_redflag(self):
481
'''Check uses redflag fields'''
482
if not self.is_snap2 or 'uses' not in self.policies:
480
def check_slots_redflag(self):
481
'''Check slots redflag fields'''
482
if not self.is_snap2 or 'slots' not in self.policies:
485
for slot in self.policies['uses']:
485
for slot in self.policies['slots']:
487
487
n = self._get_check_name('redflag_fields', extra=slot)
492
if 'security-override' in self.policies['uses'][slot]:
492
if 'security-override' in self.policies['slots'][slot]:
493
493
attrib = 'security-override'
494
elif 'security-policy' in self.policies['uses'][slot]:
494
elif 'security-policy' in self.policies['slots'][slot]:
495
495
attrib = 'security-policy'
500
500
self._add_result(t, n, s, manual_review=m)
502
def check_apps_uses_mapped_migration(self):
503
'''Check apps uses mapped migration skill'''
502
def check_apps_slots_mapped_oldsecurity(self):
503
'''Check apps slots mapped old-security interface'''
504
504
if not self.is_snap2 or 'apps' not in self.policies:
507
507
for app in self.policies['apps']:
508
for slot_ref in self.policies['apps'][app]['uses']:
508
for slot_ref in self.policies['apps'][app]['slots']:
510
n = self._get_check_name("app_uses", app=app, extra=slot_ref)
510
n = self._get_check_name("app_slots", app=app, extra=slot_ref)
512
512
if not isinstance(slot_ref, str):
513
513
continue # checked via sr_lint.py
514
elif slot_ref not in self.policies['uses']:
514
elif slot_ref not in self.policies['slots']:
516
s = "slot reference '%s' not in toplevel 'uses'" % slot_ref
516
s = "slot reference '%s' not in toplevel 'slots'" % slot_ref
517
517
self._add_result(t, n, s)
519
519
def check_apparmor_profile_name_length(self):