[apparmor] [patch] AARE class

Christian Boltz apparmor at cboltz.de
Wed Oct 21 22:48:14 UTC 2015


Hello,

the AARE class is meant to handle the internals of path AppArmor regexes
at various places / rule types (filename, signal peer etc.). The goal is
to use it in rule classes to hide all regex magic, so that the rule
class can just use the match() method.

Expanding variables is on my TODO list - the parameter already exists,
but they aren't handled or expanded yet. (AFAIK the existing code also
doesn't do that.)

The reason for delaying re.compile to match() is performance - I'd guess
a logprof run match()es only for profiles with existing log events, so
we can save 90% of the re.compile() calls.

Another possible optimization (also on my TODO list) is to check if the
given path is a regex (contains {...,...}, [...], *, **, ?) or if we can
do a plain string comparison.

The patch also includes some tests which should give you an idea how the
class will be used.


Note: This is a proof-of-concept patch. I won't object if someone sends
an ack, but the main goal of this mail is to get feedback if the way
I've chosen looks sane or if I should change some things ;-)



[ POC_aare-class-and-tests.diff ]

=== modified file ./utils/apparmor/aare.py
--- utils/apparmor/aare.py      2015-10-04 23:27:26.940248676 +0200
+++ utils/apparmor/aare.py      2015-10-20 19:58:45.330137525 +0200
@@ -0,0 +1,46 @@
+# ----------------------------------------------------------------------
+#    Copyright (C) 2015 Christian Boltz <apparmor at cboltz.de>
+#
+#    This program is free software; you can redistribute it and/or
+#    modify it under the terms of version 2 of the GNU General Public
+#    License as published by the Free Software Foundation.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+# ----------------------------------------------------------------------
+
+import re
+
+from apparmor.common import convert_regexp, AppArmorException
+
+class AARE(object):
+    '''AARE (AppArmor Regular Expression) wrapper class'''
+
+    def __init__(self, regex, variables, is_path):
+        '''create an AARE instance for the given AppArmor regex, using the specified variables when matching.
+        If is_path is true, the regex is expected to be a path and therefore must start with / or a variable.'''
+
+        if is_path:
+            if regex.startswith('/'):
+                pass
+            elif regex.startswith('@{'):
+                pass  # XXX ideally check variable content - each part must start with / - or another variable, which must start with /
+            else:
+                raise AppArmorException("Path doesn't start with / or variable: %s" % regex)
+
+        self.regex = regex
+
+        self.regex_compiled = None  # done on first use in match() - that saves us some re.compile() calls
+        self.variables = variables  # XXX not used yet
+
+    def match(self, expression):
+        '''check if a given expression matches the regex'''
+
+        if self.regex_compiled is None:
+            self.regex_compiled = re.compile(convert_regexp(self.regex))
+
+        return self.regex_compiled.match(expression)
+
=== modified file ./utils/test/test-aare.py
--- utils/test/test-aare.py     2015-10-11 20:56:56.817732630 +0200
+++ utils/test/test-aare.py     2015-10-20 19:55:44.731555468 +0200
@@ -14,7 +14,8 @@
 from common_test import AATest, setup_all_loops
 
 import re
-from apparmor.common import convert_regexp
+from apparmor.common import convert_regexp, AppArmorException
+from apparmor.aare import AARE
 
 class TestConvert_regexp(AATest):
     tests = [
@@ -117,6 +118,32 @@
         parsed_regex = re.compile(convert_regexp(regex))
         self.assertEqual(bool(parsed_regex.search(path)), expected, 'Incorrectly Parsed regex: %s' %regex)
 
+        aare_obj = AARE(regex, set(), True)
+        self.assertEqual(bool(aare_obj.match(path)), expected, 'Incorrectly parsed AARE object: %s' % regex)
+
+    def test_multi_usage(self):
+        aare_obj = AARE('/foo/*', set(), True)
+        self.assertTrue(aare_obj.match('/foo/bar'))
+        self.assertFalse(aare_obj.match('/foo/bar/'))
+        self.assertTrue(aare_obj.match('/foo/asdf'))
+
+class TestAAREIsPath(AATest):
+    def test_path(self):
+        aare_obj = AARE('/foo*', set(), True)
+        self.assertTrue(aare_obj.match('/foobar'))
+
+    def test_path_var(self):
+        aare_obj = AARE('@{PROC}/', set(), True)
+        self.assertFalse(aare_obj.match('/foobar'))
+
+    def test_non_path(self):
+        aare_obj = AARE('foo*', set(), False)
+        self.assertTrue(aare_obj.match('foobar'))
+
+    def test_path_missing_slash(self):
+        with self.assertRaises(AppArmorException):
+            AARE('foo*', set(), True)
+
 
 setup_all_loops(__name__)
 if __name__ == '__main__':


Regards,

Christian Boltz
-- 
Übrigens gibt es jetzt eine Briefmarke von Bill Gates. Leider klebt
die nicht so richtig. Eine unabhängige Kommission hat inzwischen
festgestellt, daß die Leute immer auf die falsche Seite spucken.




More information about the AppArmor mailing list