2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-31 14:25:52 +00:00

[22/38] Add get_perms_for_path() and get_rules_for_path() to FileRuleset

- get_rules_for_path() returns all rules matching the given path
  (both exact matches and AARE matches)
- get_perms_for_path() returns the merged permissions for the given
  path and a list of paths used in the matching rules

Also add tests for these two functions.



Acked-by: Steve Beattie <steve@nxnw.org>
This commit is contained in:
Christian Boltz
2016-10-01 20:03:07 +02:00
parent 8dc09bd643
commit 435281f018
2 changed files with 169 additions and 1 deletions

View File

@@ -380,7 +380,72 @@ class FileRule(BaseRule):
class FileRuleset(BaseRuleset):
'''Class to handle and store a collection of file rules'''
pass
def get_rules_for_path(self, path, audit=False, deny=False):
'''Get all rules matching the given path
path can be str or AARE
If audit is True, only return rules with the audit flag set.
If deny is True, only return matching deny rules'''
matching_rules = FileRuleset()
for rule in self.rules:
if (rule.all_paths or rule.path.match(path)) and ((not deny) or rule.deny) and ((not audit) or rule.audit):
matching_rules.add(rule)
return matching_rules
def get_perms_for_path(self, path, audit=False, deny=False):
'''Get the summarized permissions of all rules matching the given path, and the list of paths involved in the calculation
path can be str or AARE
If audit is True, only analyze rules with the audit flag set.
If deny is True, only analyze matching deny rules
Returns {'allow': {'owner': set_of_perms, 'all': set_of_perms},
'deny': {'owner': set_of_perms, 'all': set_of_perms},
'path': involved_paths}
Note: exec rules and exec/link target are not honored!
'''
# XXX do we need to honor the link target?
perms = {
'allow': {'owner': set(), 'all': set() },
'deny': {'owner': set(), 'all': set() },
}
all_perms = {
'allow': {'owner': False, 'all': False },
'deny': {'owner': False, 'all': False },
}
paths = set()
matching_rules = self.get_rules_for_path(path, audit, deny)
for rule in matching_rules.rules:
allow_or_deny = 'allow'
if rule.deny:
allow_or_deny = 'deny'
owner_or_all = 'all'
if rule.owner:
owner_or_all = 'owner'
if rule.all_perms:
all_perms[allow_or_deny][owner_or_all] = True
elif rule.perms:
perms[allow_or_deny][owner_or_all] = perms[allow_or_deny][owner_or_all].union(rule.perms)
paths.add(rule.path.regex)
allow = {}
deny = {}
for who in ['all', 'owner']:
if all_perms['allow'][who]:
allow[who] = FileRule.ALL
else:
allow[who] = perms['allow'][who]
if all_perms['deny'][who]:
deny[who] = FileRule.ALL
else:
deny[who] = perms['deny'][who]
return {'allow': allow, 'deny': deny, 'paths': paths}
def split_perms(perm_string, deny):

View File

@@ -869,6 +869,109 @@ class FileRulesTest(AATest):
#class FileDeleteTest(AATest):
# pass
class FileGetRulesForPath(AATest):
tests = [
# path audit deny expected
(('/etc/foo/dovecot.conf', False, False), ['/etc/foo/* r,', '/etc/foo/dovecot.conf rw,', '']),
(('/etc/foo/foo.conf', False, False), ['/etc/foo/* r,', '']),
(('/etc/foo/dovecot-database.conf.ext', False, False), ['/etc/foo/* r,', '/etc/foo/dovecot-database.conf.ext w,', '']),
(('/etc/foo/auth.d/authfoo.conf', False, False), ['/etc/foo/{auth,conf}.d/*.conf r,','/etc/foo/{auth,conf}.d/authfoo.conf w,', '']),
(('/etc/foo/dovecot-deny.conf', False, False), ['deny /etc/foo/dovecot-deny.conf r,', '', '/etc/foo/* r,', '']),
(('/foo/bar', False, True ), [ ]),
(('/etc/foo/dovecot-deny.conf', False, True ), ['deny /etc/foo/dovecot-deny.conf r,', '']),
(('/etc/foo/foo.conf', False, True ), [ ]),
(('/etc/foo/owner.conf', False, False), ['/etc/foo/* r,', 'owner /etc/foo/owner.conf w,', '']),
]
def _run_test(self, params, expected):
rules = [
'/etc/foo/* r,',
'/etc/foo/dovecot.conf rw,',
'/etc/foo/{auth,conf}.d/*.conf r,',
'/etc/foo/{auth,conf}.d/authfoo.conf w,',
'/etc/foo/dovecot-database.conf.ext w,',
'owner /etc/foo/owner.conf w,',
'deny /etc/foo/dovecot-deny.conf r,',
]
ruleset = FileRuleset()
for rule in rules:
ruleset.add(FileRule.parse(rule))
matching = ruleset.get_rules_for_path(params[0], params[1], params[2])
self. assertEqual(matching.get_clean(), expected)
class FileGetPermsForPath_1(AATest):
tests = [
# path audit deny expected
(('/etc/foo/dovecot.conf', False, False), {'allow': {'all': {'r', 'w'}, 'owner': set() }, 'deny': {'all': set(), 'owner': set() }, 'paths': {'/etc/foo/*', '/etc/foo/dovecot.conf' } }),
(('/etc/foo/foo.conf', False, False), {'allow': {'all': {'r' }, 'owner': set() }, 'deny': {'all': set(), 'owner': set() }, 'paths': {'/etc/foo/*' } }),
(('/etc/foo/dovecot-database.conf.ext', False, False), {'allow': {'all': {'r', 'w'}, 'owner': set() }, 'deny': {'all': set(), 'owner': set() }, 'paths': {'/etc/foo/*', '/etc/foo/dovecot-database.conf.ext' } }),
(('/etc/foo/auth.d/authfoo.conf', False, False), {'allow': {'all': {'r', 'w'}, 'owner': set() }, 'deny': {'all': set(), 'owner': set() }, 'paths': {'/etc/foo/{auth,conf}.d/*.conf', '/etc/foo/{auth,conf}.d/authfoo.conf' } }),
(('/etc/foo/dovecot-deny.conf', False, False), {'allow': {'all': {'r' }, 'owner': set() }, 'deny': {'all': {'r' }, 'owner': set() }, 'paths': {'/etc/foo/*', '/etc/foo/dovecot-deny.conf' } }),
(('/foo/bar', False, True ), {'allow': {'all': set(), 'owner': set() }, 'deny': {'all': set(), 'owner': set() }, 'paths': set() }),
(('/etc/foo/dovecot-deny.conf', False, True ), {'allow': {'all': set(), 'owner': set() }, 'deny': {'all': {'r' }, 'owner': set() }, 'paths': {'/etc/foo/dovecot-deny.conf' } }),
(('/etc/foo/foo.conf', False, True ), {'allow': {'all': set(), 'owner': set() }, 'deny': {'all': set(), 'owner': set() }, 'paths': set() }),
]
def _run_test(self, params, expected):
rules = [
'/etc/foo/* r,',
'/etc/foo/dovecot.conf rw,',
'/etc/foo/{auth,conf}.d/*.conf r,',
'/etc/foo/{auth,conf}.d/authfoo.conf w,',
'/etc/foo/dovecot-database.conf.ext w,',
'deny /etc/foo/dovecot-deny.conf r,',
'/usr/lib/dovecot/config ix,',
]
ruleset = FileRuleset()
for rule in rules:
ruleset.add(FileRule.parse(rule))
perms = ruleset.get_perms_for_path(params[0], params[1], params[2])
self. assertEqual(perms, expected)
class FileGetPermsForPath_2(AATest):
tests = [
# path audit deny expected
(('/etc/foo/dovecot.conf', False, False), {'allow': {'all': FileRule.ALL, 'owner': set() }, 'deny': {'all': FileRule.ALL, 'owner': set() }, 'paths': {'/etc/foo/*', '/etc/foo/dovecot.conf' } }),
(('/etc/foo/dovecot.conf', True, False), {'allow': {'all': {'r', 'w'}, 'owner': set() }, 'deny': {'all': set(), 'owner': set() }, 'paths': {'/etc/foo/dovecot.conf' } }),
(('/etc/foo/foo.conf', False, False), {'allow': {'all': FileRule.ALL, 'owner': set() }, 'deny': {'all': FileRule.ALL, 'owner': set() }, 'paths': {'/etc/foo/*' } }),
(('/etc/foo/dovecot-database.conf.ext', False, False), {'allow': {'all': FileRule.ALL, 'owner': set() }, 'deny': {'all': FileRule.ALL, 'owner': set() }, 'paths': {'/etc/foo/*', '/etc/foo/dovecot-database.conf.ext' } }),
(('/etc/foo/auth.d/authfoo.conf', False, False), {'allow': {'all': FileRule.ALL, 'owner': set() }, 'deny': {'all': FileRule.ALL, 'owner': set() }, 'paths': {'/etc/foo/{auth,conf}.d/*.conf', '/etc/foo/{auth,conf}.d/authfoo.conf' } }),
(('/etc/foo/auth.d/authfoo.conf', True, False), {'allow': {'all': {'w' }, 'owner': set() }, 'deny': {'all': set(), 'owner': set() }, 'paths': {'/etc/foo/{auth,conf}.d/authfoo.conf' } }),
(('/etc/foo/dovecot-deny.conf', False, False), {'allow': {'all': FileRule.ALL, 'owner': set() }, 'deny': {'all': FileRule.ALL, 'owner': set() }, 'paths': {'/etc/foo/*', '/etc/foo/dovecot-deny.conf' } }),
(('/foo/bar', False, True ), {'allow': {'all': set(), 'owner': set() }, 'deny': {'all': FileRule.ALL, 'owner': set() }, 'paths': set() }),
(('/etc/foo/dovecot-deny.conf', False, True ), {'allow': {'all': set(), 'owner': set() }, 'deny': {'all': FileRule.ALL, 'owner': set() }, 'paths': {'/etc/foo/dovecot-deny.conf' } }),
(('/etc/foo/foo.conf', False, True ), {'allow': {'all': set(), 'owner': set() }, 'deny': {'all': FileRule.ALL, 'owner': set() }, 'paths': set() }),
# (('/etc/foo/owner.conf', False, True ), {'allow': {'all': set(), 'owner': {'w'} }, 'deny': {'all': FileRule.ALL, 'owner': set() }, 'paths': {'/etc/foo/owner.conf' } }), # XXX doen't work yet
]
def _run_test(self, params, expected):
rules = [
'/etc/foo/* r,',
'audit /etc/foo/dovecot.conf rw,',
'/etc/foo/{auth,conf}.d/*.conf r,',
'audit /etc/foo/{auth,conf}.d/authfoo.conf w,',
'/etc/foo/dovecot-database.conf.ext w,',
'deny /etc/foo/dovecot-deny.conf r,',
'file,',
'owner /etc/foo/owner.conf w,',
'deny file,',
]
ruleset = FileRuleset()
for rule in rules:
ruleset.add(FileRule.parse(rule))
perms = ruleset.get_perms_for_path(params[0], params[1], params[2])
self. assertEqual(perms, expected)
setup_all_loops(__name__)
if __name__ == '__main__':
unittest.main(verbosity=2)