Merge Improve and simplify profile parsing in the tools

This is done by introducing a match_line_against_rule_classes() function to get of repeating code in parse_profile_data().

A side effect is a better separation of preamble and profile data, which needed changes at several places - especially include rules in the preamble were funny\[tm\].

MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/719
Acked-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
John Johansen 2021-03-14 11:59:36 +00:00
commit 3f51877220
6 changed files with 116 additions and 144 deletions

View file

@ -46,15 +46,13 @@ from apparmor.regex import (RE_PROFILE_START, RE_PROFILE_END,
RE_PROFILE_UNIX, RE_RULE_HAS_COMMA, RE_HAS_COMMENT_SPLIT,
strip_quotes, parse_profile_start_line, re_match_include )
from apparmor.profile_list import ProfileList
from apparmor.profile_list import ProfileList, preamble_ruletypes
from apparmor.profile_storage import ProfileStorage, add_or_remove_flag, ruletypes
import apparmor.rules as aarules
from apparmor.rule.abi import AbiRule
from apparmor.rule.alias import AliasRule
from apparmor.rule.boolean import BooleanRule
from apparmor.rule.capability import CapabilityRule
from apparmor.rule.change_profile import ChangeProfileRule
from apparmor.rule.dbus import DbusRule
@ -62,9 +60,7 @@ from apparmor.rule.file import FileRule
from apparmor.rule.include import IncludeRule
from apparmor.rule.network import NetworkRule
from apparmor.rule.ptrace import PtraceRule
from apparmor.rule.rlimit import RlimitRule
from apparmor.rule.signal import SignalRule
from apparmor.rule.variable import VariableRule
from apparmor.rule import quote_if_needed
# setup module translations
@ -871,7 +867,7 @@ def ask_exec(hashlog):
prof_filename = get_profile_filename_from_profile_name(profile)
if prof_filename and active_profiles.files.get(prof_filename):
sev_db.set_variables(active_profiles.get_all_merged_variables(prof_filename, include_list_recursive(active_profiles.files[prof_filename])))
sev_db.set_variables(active_profiles.get_all_merged_variables(prof_filename, include_list_recursive(active_profiles.files[prof_filename], True)))
else:
sev_db.set_variables( {} )
@ -1075,7 +1071,7 @@ def ask_the_questions(log_dict):
for profile in sorted(log_dict[aamode].keys()):
prof_filename = get_profile_filename_from_profile_name(profile)
if prof_filename and active_profiles.files.get(prof_filename):
sev_db.set_variables(active_profiles.get_all_merged_variables(prof_filename, include_list_recursive(active_profiles.files[prof_filename])))
sev_db.set_variables(active_profiles.get_all_merged_variables(prof_filename, include_list_recursive(active_profiles.files[prof_filename], True)))
else:
sev_db.set_variables( {} )
@ -1728,7 +1724,7 @@ def read_profile(file, active_profile):
debug_logger.debug("read_profile: can't read %s - skipping" % file)
return None
profile_data = parse_profile_data(data, file, 0)
profile_data = parse_profile_data(data, file, 0, True)
if profile_data and active_profile:
attach_profile_data(aa, profile_data)
@ -1826,7 +1822,7 @@ def parse_profile_start_to_storage(line, file, lineno, profile, hat):
return (profile, hat, prof_storage)
def parse_profile_data(data, file, do_include):
def parse_profile_data(data, file, do_include, in_preamble):
profile_data = hasher()
profile = None
hat = None
@ -1835,6 +1831,8 @@ def parse_profile_data(data, file, do_include):
initial_comment = ''
lastline = None
active_profiles.init_file(file)
if do_include:
profile = file
hat = file
@ -1849,8 +1847,20 @@ def parse_profile_data(data, file, do_include):
if lastline:
line = '%s %s' % (lastline, line)
lastline = None
# Starting line of a profile
if RE_PROFILE_START.search(line):
# is line handled by a *Rule class?
(rule_name, rule_obj) = match_line_against_rule_classes(line, profile, file, lineno, in_preamble)
if rule_name:
if in_preamble:
active_profiles.add_rule(file, rule_name, rule_obj)
else:
profile_data[profile][hat][rule_name].add(rule_obj)
if rule_name == 'inc_ie':
for incname in rule_obj.get_full_paths(profile_dir):
load_include(incname, in_preamble)
elif RE_PROFILE_START.search(line): # Starting line of a profile
# in_contained_hat is needed to know if we are already in a profile or not. (Simply checking if we are in a hat doesn't work,
# because something like "profile foo//bar" will set profile and hat at once, and later (wrongfully) expect another "}".
# The logic is simple and resembles a "poor man's stack" (with limited/hardcoded height).
@ -1859,6 +1869,8 @@ def parse_profile_data(data, file, do_include):
else:
in_contained_hat = False
in_preamble = False
(profile, hat, prof_storage) = parse_profile_start_to_storage(line, file, lineno, profile, hat)
if profile_data[profile].get(hat, False):
@ -1884,48 +1896,10 @@ def parse_profile_data(data, file, do_include):
else:
parsed_profiles.append(profile)
profile = None
in_preamble = True
initial_comment = ''
elif CapabilityRule.match(line):
if not profile:
raise AppArmorException(_('Syntax Error: Unexpected capability entry found in file: %(file)s line: %(line)s') % { 'file': file, 'line': lineno + 1 })
profile_data[profile][hat]['capability'].add(CapabilityRule.parse(line))
elif ChangeProfileRule.match(line):
if not profile:
raise AppArmorException(_('Syntax Error: Unexpected change profile entry found in file: %(file)s line: %(line)s') % { 'file': file, 'line': lineno + 1 })
profile_data[profile][hat]['change_profile'].add(ChangeProfileRule.parse(line))
elif AliasRule.match(line):
if profile and not do_include:
raise AppArmorException(_('Syntax Error: Unexpected alias definition found inside profile in file: %(file)s line: %(line)s') % {
'file': file, 'line': lineno + 1 })
else:
active_profiles.add_alias(file, AliasRule.parse(line))
elif RlimitRule.match(line):
if not profile:
raise AppArmorException(_('Syntax Error: Unexpected rlimit entry found in file: %(file)s line: %(line)s') % { 'file': file, 'line': lineno + 1 })
profile_data[profile][hat]['rlimit'].add(RlimitRule.parse(line))
elif BooleanRule.match(line):
if profile and not do_include:
raise AppArmorException(_('Syntax Error: Unexpected boolean definition found inside profile in file: %(file)s line: %(line)s') % {
'file': file, 'line': lineno + 1 })
else:
active_profiles.add_boolean(file, BooleanRule.parse(line))
elif VariableRule.match(line):
if profile and not do_include:
raise AppArmorException(_('Syntax Error: Unexpected variable definition found inside profile in file: %(file)s line: %(line)s') % {
'file': file, 'line': lineno + 1 })
else:
active_profiles.add_variable(file, VariableRule.parse(line))
elif RE_PROFILE_CONDITIONAL.search(line):
# Conditional Boolean
pass
@ -1938,34 +1912,6 @@ def parse_profile_data(data, file, do_include):
# Conditional Boolean defined
pass
elif AbiRule.match(line):
if profile:
profile_data[profile][hat]['abi'].add(AbiRule.parse(line))
else:
active_profiles.add_abi(file, AbiRule.parse(line))
elif IncludeRule.match(line):
rule_obj = IncludeRule.parse(line)
if profile:
profile_data[profile][hat]['inc_ie'].add(rule_obj)
else:
active_profiles.add_inc_ie(file, rule_obj)
for incname in rule_obj.get_full_paths(profile_dir):
load_include(incname)
elif NetworkRule.match(line):
if not profile:
raise AppArmorException(_('Syntax Error: Unexpected network entry found in file: %(file)s line: %(line)s') % { 'file': file, 'line': lineno + 1 })
profile_data[profile][hat]['network'].add(NetworkRule.parse(line))
elif DbusRule.match(line):
if not profile:
raise AppArmorException(_('Syntax Error: Unexpected dbus entry found in file: %(file)s line: %(line)s') % {'file': file, 'line': lineno + 1 })
profile_data[profile][hat]['dbus'].add(DbusRule.parse(line))
elif RE_PROFILE_MOUNT.search(line):
matches = RE_PROFILE_MOUNT.search(line).groups()
@ -1988,18 +1934,6 @@ def parse_profile_data(data, file, do_include):
mount_rules.append(mount_rule)
profile_data[profile][hat][allow]['mount'] = mount_rules
elif SignalRule.match(line):
if not profile:
raise AppArmorException(_('Syntax Error: Unexpected signal entry found in file: %(file)s line: %(line)s') % { 'file': file, 'line': lineno + 1 })
profile_data[profile][hat]['signal'].add(SignalRule.parse(line))
elif PtraceRule.match(line):
if not profile:
raise AppArmorException(_('Syntax Error: Unexpected ptrace entry found in file: %(file)s line: %(line)s') % { 'file': file, 'line': lineno + 1 })
profile_data[profile][hat]['ptrace'].add(PtraceRule.parse(line))
elif RE_PROFILE_PIVOT_ROOT.search(line):
matches = RE_PROFILE_PIVOT_ROOT.search(line).groups()
@ -2097,13 +2031,6 @@ def parse_profile_data(data, file, do_include):
# keep line as part of initial_comment (if we ever support writing abstractions, we should update serialize_profile())
initial_comment = initial_comment + line + '\n'
elif FileRule.match(line):
# leading permissions could look like a keyword, therefore handle file rules after everything else
if not profile:
raise AppArmorException(_('Syntax Error: Unexpected path entry found in file: %(file)s line: %(line)s') % { 'file': file, 'line': lineno + 1 })
profile_data[profile][hat]['file'].add(FileRule.parse(line))
elif not RE_RULE_HAS_COMMA.search(line):
# Bah, line continues on to the next line
if RE_HAS_COMMENT_SPLIT.search(line):
@ -2134,6 +2061,42 @@ def parse_profile_data(data, file, do_include):
return profile_data
def match_line_against_rule_classes(line, profile, file, lineno, in_preamble):
''' handle all lines handled by *Rule classes '''
for rule_name in [
'abi',
'alias',
'boolean',
'variable',
'inc_ie',
'capability',
'change_profile',
'dbus',
'file', # file rules need to be parsed after variable rules
'network',
'ptrace',
'rlimit',
'signal',
]:
if rule_name in ruletypes:
rule_class = ruletypes[rule_name]['rule']
else:
rule_class = preamble_ruletypes[rule_name]['rule']
if rule_class.match(line):
if not in_preamble and rule_name not in ruletypes:
raise AppArmorException(_('Syntax Error: Unexpected %(rule)s definition found inside profile in file: %(file)s line: %(line)s') % { 'file': file, 'line': lineno + 1, 'rule': rule_name })
if in_preamble and rule_name not in preamble_ruletypes:
raise AppArmorException(_('Syntax Error: Unexpected %(rule)s entry found in file: %(file)s line: %(line)s') % { 'file': file, 'line': lineno + 1, 'rule': rule_name })
rule_obj = rule_class.parse(line)
return(rule_name, rule_obj)
return(None, None)
def parse_mount_rule(line):
# XXX Do real parsing here
return aarules.Raw_Mount_Rule(line)
@ -2296,7 +2259,7 @@ def write_profile(profile, is_attachment=False):
original_aa[profile] = deepcopy(aa[profile])
def include_list_recursive(profile):
def include_list_recursive(profile, in_preamble=False):
''' get a list of all includes in a profile and its included files '''
includelist = profile['inc_ie'].get_all_full_paths(profile_dir)
@ -2309,7 +2272,12 @@ def include_list_recursive(profile):
continue
full_list.append(incname)
for childinc in include[incname][incname]['inc_ie'].rules:
if in_preamble:
look_at = active_profiles.files[incname]
else:
look_at = include[incname][incname]
for childinc in look_at['inc_ie'].rules:
for childinc_file in childinc.get_full_paths(profile_dir):
if childinc_file not in full_list:
includelist += [childinc_file]
@ -2440,7 +2408,7 @@ def include_dir_filelist(include_name):
return files
def load_include(incname):
def load_include(incname, in_preamble=False):
load_includeslist = [incname]
while load_includeslist:
incfile = load_includeslist.pop(0)
@ -2451,7 +2419,7 @@ def load_include(incname):
pass # already read, do nothing
elif os.path.isfile(incfile):
data = get_include_data(incfile)
incdata = parse_profile_data(data, incfile, True)
incdata = parse_profile_data(data, incfile, True, in_preamble)
attach_profile_data(include, incdata)
#If the include is a directory means include all subfiles
elif os.path.isdir(incfile):
@ -2475,10 +2443,10 @@ def get_subdirectories(current_dir):
return os.walk(current_dir).__next__()[1]
def loadincludes():
loadincludes_dir('tunables')
loadincludes_dir('abstractions')
loadincludes_dir('tunables', True)
loadincludes_dir('abstractions', False)
def loadincludes_dir(subdir):
def loadincludes_dir(subdir, in_preamble):
idir = os.path.join(profile_dir, subdir)
if os.path.isdir(idir): # if directory doesn't exist, silently skip loading it
@ -2488,7 +2456,7 @@ def loadincludes_dir(subdir):
continue
else:
fi = os.path.join(dirpath, fi)
load_include(fi)
load_include(fi, in_preamble)
def glob_common(path):
globs = []

View file

@ -90,6 +90,13 @@ class ProfileList:
else:
self.files[filename]['profiles'].append(attachment)
def add_rule(self, filename, ruletype, rule):
''' Store the given rule for the given profile filename preamble '''
self.init_file(filename)
self.files[filename][ruletype].add(rule)
def add_abi(self, filename, abi_rule):
''' Store the given abi rule for the given profile filename preamble '''
@ -226,9 +233,6 @@ class ProfileList:
inc_add[filename] = mainfile_variables['+='] # variable additions from main file
for incname in all_incfiles:
if not self.files.get(incname):
continue # tunables/* only end up in self.files if they contain variable or alias definitions
inc_vars = self.files[incname]['variable'].get_merged_variables()
for var in inc_vars['=']:

View file

@ -16,16 +16,16 @@
from apparmor.common import AppArmorBug, type_is_str
from apparmor.rule.abi import AbiRuleset
from apparmor.rule.capability import CapabilityRuleset
from apparmor.rule.change_profile import ChangeProfileRuleset
from apparmor.rule.dbus import DbusRuleset
from apparmor.rule.file import FileRuleset
from apparmor.rule.include import IncludeRuleset
from apparmor.rule.network import NetworkRuleset
from apparmor.rule.ptrace import PtraceRuleset
from apparmor.rule.rlimit import RlimitRuleset
from apparmor.rule.signal import SignalRuleset
from apparmor.rule.abi import AbiRule, AbiRuleset
from apparmor.rule.capability import CapabilityRule, CapabilityRuleset
from apparmor.rule.change_profile import ChangeProfileRule, ChangeProfileRuleset
from apparmor.rule.dbus import DbusRule, DbusRuleset
from apparmor.rule.file import FileRule, FileRuleset
from apparmor.rule.include import IncludeRule, IncludeRuleset
from apparmor.rule.network import NetworkRule, NetworkRuleset
from apparmor.rule.ptrace import PtraceRule, PtraceRuleset
from apparmor.rule.rlimit import RlimitRule, RlimitRuleset
from apparmor.rule.signal import SignalRule, SignalRuleset
from apparmor.rule import quote_if_needed
@ -34,16 +34,16 @@ from apparmor.translations import init_translation
_ = init_translation()
ruletypes = {
'abi': {'ruleset': AbiRuleset},
'inc_ie': {'ruleset': IncludeRuleset},
'capability': {'ruleset': CapabilityRuleset},
'change_profile': {'ruleset': ChangeProfileRuleset},
'dbus': {'ruleset': DbusRuleset},
'file': {'ruleset': FileRuleset},
'network': {'ruleset': NetworkRuleset},
'ptrace': {'ruleset': PtraceRuleset},
'rlimit': {'ruleset': RlimitRuleset},
'signal': {'ruleset': SignalRuleset},
'abi': {'rule': AbiRule, 'ruleset': AbiRuleset, },
'inc_ie': {'rule': IncludeRule, 'ruleset': IncludeRuleset, },
'capability': {'rule': CapabilityRule, 'ruleset': CapabilityRuleset, },
'change_profile': {'rule': ChangeProfileRule, 'ruleset': ChangeProfileRuleset, },
'dbus': {'rule': DbusRule, 'ruleset': DbusRuleset, },
'file': {'rule': FileRule, 'ruleset': FileRuleset, },
'network': {'rule': NetworkRule, 'ruleset': NetworkRuleset, },
'ptrace': {'rule': PtraceRule, 'ruleset': PtraceRuleset, },
'rlimit': {'rule': RlimitRule, 'ruleset': RlimitRuleset, },
'signal': {'rule': SignalRule, 'ruleset': SignalRuleset, },
}
class ProfileStorage:

View file

@ -521,7 +521,7 @@ class AaTest_parse_profile_start_errors(AATest):
class AaTest_parse_profile_data(AATest):
def test_parse_empty_profile_01(self):
prof = parse_profile_data('/foo {\n}\n'.split(), 'somefile', False)
prof = parse_profile_data('/foo {\n}\n'.split(), 'somefile', False, False)
self.assertEqual(list(prof.keys()), ['/foo'])
self.assertEqual(list(prof['/foo'].keys()), ['/foo'])
@ -532,20 +532,20 @@ class AaTest_parse_profile_data(AATest):
def test_parse_duplicate_profile(self):
with self.assertRaises(AppArmorException):
# file contains two profiles with the same name
parse_profile_data('profile /foo {\n}\nprofile /foo {\n}\n'.split(), 'somefile', False)
parse_profile_data('profile /foo {\n}\nprofile /foo {\n}\n'.split(), 'somefile', False, False)
def test_parse_duplicate_child_profile(self):
with self.assertRaises(AppArmorException):
# file contains two child profiles with the same name
parse_profile_data('profile /foo {\nprofile /bar {\n}\nprofile /bar {\n}\n}\n'.split(), 'somefile', False)
parse_profile_data('profile /foo {\nprofile /bar {\n}\nprofile /bar {\n}\n}\n'.split(), 'somefile', False, False)
def test_parse_duplicate_hat(self):
with self.assertRaises(AppArmorException):
# file contains two hats with the same name
parse_profile_data('profile /foo {\n^baz {\n}\n^baz {\n}\n}\n'.split(), 'somefile', False)
parse_profile_data('profile /foo {\n^baz {\n}\n^baz {\n}\n}\n'.split(), 'somefile', False, False)
def test_parse_xattrs_01(self):
prof = parse_profile_data('/foo xattrs=(user.bar=bar) {\n}\n'.split(), 'somefile', False)
prof = parse_profile_data('/foo xattrs=(user.bar=bar) {\n}\n'.split(), 'somefile', False, False)
self.assertEqual(list(prof.keys()), ['/foo'])
self.assertEqual(list(prof['/foo'].keys()), ['/foo'])
@ -555,7 +555,7 @@ class AaTest_parse_profile_data(AATest):
self.assertEqual(prof['/foo']['/foo']['xattrs'], 'user.bar=bar')
def test_parse_xattrs_02(self):
prof = parse_profile_data('/foo xattrs=(user.bar=bar user.foo=*) {\n}\n'.split(), 'somefile', False)
prof = parse_profile_data('/foo xattrs=(user.bar=bar user.foo=*) {\n}\n'.split(), 'somefile', False, False)
self.assertEqual(list(prof.keys()), ['/foo'])
self.assertEqual(list(prof['/foo'].keys()), ['/foo'])
@ -566,7 +566,7 @@ class AaTest_parse_profile_data(AATest):
def test_parse_xattrs_03(self):
d = '/foo xattrs=(user.bar=bar) flags=(complain) {\n}\n'
prof = parse_profile_data(d.split(), 'somefile', False)
prof = parse_profile_data(d.split(), 'somefile', False, False)
self.assertEqual(list(prof.keys()), ['/foo'])
self.assertEqual(list(prof['/foo'].keys()), ['/foo'])
@ -579,7 +579,7 @@ class AaTest_parse_profile_data(AATest):
with self.assertRaises(AppArmorException):
# flags before xattrs
d = '/foo flags=(complain) xattrs=(user.bar=bar) {\n}\n'
parse_profile_data(d.split(), 'somefile', False)
parse_profile_data(d.split(), 'somefile', False, False)
class AaTest_write_header(AATest):
tests = [

View file

@ -430,12 +430,12 @@ class TestParseParserTests(AATest):
apparmor.active_profiles.init_file(params['file'])
if expected:
apparmor.parse_profile_data(data, params['file'], 0)
apparmor.parse_profile_data(data, params['file'], 0, True)
apparmor.active_profiles.get_all_merged_variables(params['file'], apparmor.include_list_recursive(apparmor.active_profiles.files[params['file']]))
else:
with self.assertRaises(AppArmorException):
apparmor.parse_profile_data(data, params['file'], 0)
apparmor.parse_profile_data(data, params['file'], 0, True)
apparmor.active_profiles.get_all_merged_variables(params['file'], apparmor.include_list_recursive(apparmor.active_profiles.files[params['file']]))
def parse_test_profiles(file_with_path):

View file

@ -344,7 +344,7 @@ class AaTest_get_all_merged_variables(AATest):
def test_unchanged(self):
self._load_profiles()
prof_filename = os.path.join(self.profile_dir, 'usr.sbin.dnsmasq')
vars = apparmor.aa.active_profiles.get_all_merged_variables(os.path.join(self.profile_dir, 'usr.sbin.dnsmasq'), apparmor.aa.include_list_recursive(apparmor.aa.active_profiles.files[prof_filename]))
vars = apparmor.aa.active_profiles.get_all_merged_variables(os.path.join(self.profile_dir, 'usr.sbin.dnsmasq'), apparmor.aa.include_list_recursive(apparmor.aa.active_profiles.files[prof_filename], True))
self.assertEqual(vars['@{TFTP_DIR}'], {'/var/tftp', '/srv/tftp', '/srv/tftpboot'})
self.assertEqual(vars['@{HOME}'], {'@{HOMEDIRS}/*/', '/root/'})
@ -352,7 +352,7 @@ class AaTest_get_all_merged_variables(AATest):
write_file(self.profile_dir, 'tunables/home.d/extend_home', '@{HOME} += /my/castle/')
self._load_profiles()
prof_filename = os.path.join(self.profile_dir, 'usr.sbin.dnsmasq')
vars = apparmor.aa.active_profiles.get_all_merged_variables(os.path.join(self.profile_dir, 'usr.sbin.dnsmasq'), apparmor.aa.include_list_recursive(apparmor.aa.active_profiles.files[prof_filename]))
vars = apparmor.aa.active_profiles.get_all_merged_variables(os.path.join(self.profile_dir, 'usr.sbin.dnsmasq'), apparmor.aa.include_list_recursive(apparmor.aa.active_profiles.files[prof_filename], True))
self.assertEqual(vars['@{TFTP_DIR}'], {'/var/tftp', '/srv/tftp', '/srv/tftpboot'})
self.assertEqual(vars['@{HOME}'], {'@{HOMEDIRS}/*/', '/root/', '/my/castle/'})
@ -361,7 +361,7 @@ class AaTest_get_all_merged_variables(AATest):
write_file(self.profile_dir, 'tunables/home.d/moving_around', '@{HOME} += /on/the/road/')
self._load_profiles()
prof_filename = os.path.join(self.profile_dir, 'usr.sbin.dnsmasq')
vars = apparmor.aa.active_profiles.get_all_merged_variables(os.path.join(self.profile_dir, 'usr.sbin.dnsmasq'), apparmor.aa.include_list_recursive(apparmor.aa.active_profiles.files[prof_filename]))
vars = apparmor.aa.active_profiles.get_all_merged_variables(os.path.join(self.profile_dir, 'usr.sbin.dnsmasq'), apparmor.aa.include_list_recursive(apparmor.aa.active_profiles.files[prof_filename], True))
self.assertEqual(vars['@{TFTP_DIR}'], {'/var/tftp', '/srv/tftp', '/srv/tftpboot'})
self.assertEqual(vars['@{HOME}'], {'@{HOMEDIRS}/*/', '/root/', '/my/castle/', '/on/the/road/'})
@ -370,7 +370,7 @@ class AaTest_get_all_merged_variables(AATest):
write_file(self.profile_dir, 'dummy_profile', 'include <tunables/global>\n@{HOME} += /in/the/profile/')
self._load_profiles()
prof_filename = os.path.join(self.profile_dir, 'dummy_profile')
vars = apparmor.aa.active_profiles.get_all_merged_variables(os.path.join(self.profile_dir, 'dummy_profile'), apparmor.aa.include_list_recursive(apparmor.aa.active_profiles.files[prof_filename]))
vars = apparmor.aa.active_profiles.get_all_merged_variables(os.path.join(self.profile_dir, 'dummy_profile'), apparmor.aa.include_list_recursive(apparmor.aa.active_profiles.files[prof_filename], True))
self.assertEqual(vars.get('@{TFTP_DIR}', None), None)
self.assertEqual(vars['@{HOME}'], {'@{HOMEDIRS}/*/', '/root/', '/my/castle/', '/in/the/profile/'})
@ -379,14 +379,14 @@ class AaTest_get_all_merged_variables(AATest):
self._load_profiles()
prof_filename = os.path.join(self.profile_dir, 'usr.sbin.dnsmasq')
with self.assertRaises(AppArmorException):
apparmor.aa.active_profiles.get_all_merged_variables(os.path.join(self.profile_dir, 'usr.sbin.dnsmasq'), apparmor.aa.include_list_recursive(apparmor.aa.active_profiles.files[prof_filename]))
apparmor.aa.active_profiles.get_all_merged_variables(os.path.join(self.profile_dir, 'usr.sbin.dnsmasq'), apparmor.aa.include_list_recursive(apparmor.aa.active_profiles.files[prof_filename], True))
def test_add_to_nonexisting(self):
write_file(self.profile_dir, 'tunables/home.d/no_such_var', '@{NO_SUCH_HOME} += /my/castle/') # add to non-existing variable
self._load_profiles()
prof_filename = os.path.join(self.profile_dir, 'usr.sbin.dnsmasq')
with self.assertRaises(AppArmorException):
apparmor.aa.active_profiles.get_all_merged_variables(os.path.join(self.profile_dir, 'usr.sbin.dnsmasq'), apparmor.aa.include_list_recursive(apparmor.aa.active_profiles.files[prof_filename]))
apparmor.aa.active_profiles.get_all_merged_variables(os.path.join(self.profile_dir, 'usr.sbin.dnsmasq'), apparmor.aa.include_list_recursive(apparmor.aa.active_profiles.files[prof_filename], True))
def test_vars_from_nonexisting_profile(self):
with self.assertRaises(AppArmorBug):