Add match_line_against_rule_classes()

... to handle parsing of lines that are managed with a *Rule

This needs 'ruletypes' to also know about *Rule, not only about
*Ruleset.

Also switch over handling of most rules that live inside a profile from
parse_profile() to match_line_against_rule_classes() to make
parse_profile() more readable.

Exceptions are:
- include and abi, which can also exist in the preamble
- file rules, because they'd need to be handled later (after variable
  definitions)
This commit is contained in:
Christian Boltz 2020-12-26 23:36:03 +01:00
parent 089b266c03
commit d442620102
Failed to generate hash of commit
2 changed files with 54 additions and 65 deletions

View file

@ -62,7 +62,6 @@ 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
@ -1849,8 +1848,13 @@ 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)
if rule_name:
profile_data[profile][hat][rule_name].add(rule_obj)
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).
@ -1887,18 +1891,6 @@ def parse_profile_data(data, file, do_include):
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') % {
@ -1906,12 +1898,6 @@ def parse_profile_data(data, file, do_include):
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') % {
@ -1954,18 +1940,6 @@ def parse_profile_data(data, file, do_include):
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 +1962,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()
@ -2134,6 +2096,33 @@ def parse_profile_data(data, file, do_include):
return profile_data
def match_line_against_rule_classes(line, profile, file, lineno):
''' handle all lines handled by *Rule classes '''
for rule_name in [
# 'abi',
# 'inc_ie',
'capability',
'change_profile',
'dbus',
# 'file',
'network',
'ptrace',
'rlimit',
'signal',
]:
rule_class = ruletypes[rule_name]['rule']
if rule_class.match(line):
# if not ruletypes[rule_name]['allowed_in_preamble'] and not profile:
if not profile:
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)

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: