[apparmor] [patch] [22/38] Add get_perms_for_path() and get_rules_for_path() to FileRuleset
Christian Boltz
apparmor at cboltz.de
Fri Aug 12 21:00:11 UTC 2016
Hello,
this patch adds
- 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.
[ 22-add-get-perms-for-path.diff ]
=== modified file ./utils/apparmor/rule/file.py
--- utils/apparmor/rule/file.py 2016-05-09 22:59:25.467301579 +0200
+++ utils/apparmor/rule/file.py 2016-05-09 23:00:26.726961243 +0200
@@ -380,7 +380,72 @@
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):
=== modified file ./utils/test/test-file.py
--- utils/test/test-file.py 2016-05-09 22:59:25.467301579 +0200
+++ utils/test/test-file.py 2016-05-09 23:02:07.526401510 +0200
@@ -871,6 +871,109 @@
#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)
Regards,
Christian Boltz
--
Don't spend too much time with numbers and statistics as they both
are like a bikini; the most important part is always hidden.
[Togan Muftuoglu in opensuse-factory]
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: This is a digitally signed message part.
URL: <https://lists.ubuntu.com/archives/apparmor/attachments/20160812/33f3e706/attachment-0001.pgp>
More information about the AppArmor
mailing list