[apparmor] [Patch] utils: add limited support for af_unix rules

Steve Beattie steve at nxnw.org
Wed Aug 27 23:01:03 UTC 2014


This patch adds limited support for af_unix rules in the python
utilities, of the "don't touch them, but don't throw a python backtrace
when coming across them, either" variety. Testcases are added as well.

Signed-off-by: Steve Beattie <steve at nxnw.org>
---
 utils/apparmor/aa.py             |   27 +++++++++++++++++
 utils/apparmor/rules.py          |   15 +++++++++
 utils/test/test-regex_matches.py |   33 +++++++++++++++++++++
 utils/test/test-unix_parse.py    |   59 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 133 insertions(+), 1 deletion(-)

Index: b/utils/test/test-unix_parse.py
===================================================================
--- /dev/null
+++ b/utils/test/test-unix_parse.py
@@ -0,0 +1,59 @@
+#! /usr/bin/env python
+# ------------------------------------------------------------------
+#
+#    Copyright (C) 2014 Canonical Ltd.
+#
+#    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 published by the Free Software Foundation.
+#
+# ------------------------------------------------------------------
+
+import apparmor.aa as aa
+import unittest
+
+class AAParseUnixTest(unittest.TestCase):
+
+    def _test_parse_unix_rule(self, rule):
+        unix = aa.parse_unix_rule(rule)
+        self.assertEqual(rule, unix.serialize(),
+                'ptrace object returned "%s", expected "%s"' % (unix.serialize(), rule))
+
+    def test_parse_plain_unix_rule(self):
+        self._test_parse_unix_rule('unix,')
+
+    def test_parse_r_unix_rule(self):
+        self._test_parse_unix_rule('unix r,')
+
+    def test_parse_w_unix_rule(self):
+        self._test_parse_unix_rule('unix w,')
+
+    def test_parse_rw_unix_rule(self):
+        self._test_parse_unix_rule('unix rw,')
+
+    def test_parse_send_unix_rule(self):
+        self._test_parse_unix_rule('unix send,')
+
+    def test_parse_receive_unix_rule(self):
+        self._test_parse_unix_rule('unix receive,')
+
+    def test_parse_r_paren_unix_rule(self):
+        self._test_parse_unix_rule('unix (r),')
+
+    def test_parse_w_paren_unix_rule(self):
+        self._test_parse_unix_rule('unix (w),')
+
+    def test_parse_rw_paren_unix_rule(self):
+        self._test_parse_unix_rule('unix (rw),')
+
+    def test_parse_send_paren_unix_rule(self):
+        self._test_parse_unix_rule('unix (send),')
+
+    def test_parse_receive_paren_unix_rule(self):
+        self._test_parse_unix_rule('unix (receive),')
+
+    def test_parse_complex_unix_rule(self):
+        self._test_parse_unix_rule('unix (connect, receive, send) type=stream peer=(label=unconfined,addr="@/tmp/.X11-unix/X[0-9]*"),')
+
+if __name__ == '__main__':
+    unittest.main(verbosity=2)
Index: b/utils/apparmor/aa.py
===================================================================
--- a/utils/apparmor/aa.py
+++ b/utils/apparmor/aa.py
@@ -2636,6 +2636,7 @@ RE_PROFILE_MOUNT = re.compile('^\s*(audi
 RE_PROFILE_SIGNAL = re.compile('^\s*(audit\s+)?(allow\s+|deny\s+)?(signal\s*,|signal\s+[^#]*\s*,)\s*(#.*)?$')
 RE_PROFILE_PTRACE = re.compile('^\s*(audit\s+)?(allow\s+|deny\s+)?(ptrace\s*,|ptrace\s+[^#]*\s*,)\s*(#.*)?$')
 RE_PROFILE_PIVOT_ROOT = re.compile('^\s*(audit\s+)?(allow\s+|deny\s+)?(pivot_root\s*,|pivot_root\s+[^#]*\s*,)\s*(#.*)?$')
+RE_PROFILE_UNIX = re.compile('^\s*(audit\s+)?(allow\s+|deny\s+)?(unix\s*,|unix\s+[^#]*\s*,)\s*(#.*)?$')
 
 # match anything that's not " or #, or matching quotes with anything except quotes inside
 __re_no_or_quoted_hash = '([^#"]|"[^"]*")*'
@@ -3110,6 +3111,28 @@ def parse_profile_data(data, file, do_in
             pivot_root_rules.append(pivot_root_rule)
             profile_data[profile][hat][allow]['pivot_root'] = pivot_root_rules
 
+        elif RE_PROFILE_UNIX.search(line):
+            matches = RE_PROFILE_UNIX.search(line).groups()
+
+            if not profile:
+                raise AppArmorException(_('Syntax Error: Unexpected unix entry found in file: %s line: %s') % (file, lineno + 1))
+
+            audit = False
+            if matches[0]:
+                audit = True
+            allow = 'allow'
+            if matches[1] and matches[1].strip() == 'deny':
+                allow = 'deny'
+            unix = matches[2].strip()
+
+            unix_rule = parse_unix_rule(unix)
+            unix_rule.audit = audit
+            unix_rule.deny = (allow == 'deny')
+
+            unix_rules = profile_data[profile][hat][allow].get('unix', list())
+            unix_rules.append(unix_rule)
+            profile_data[profile][hat][allow]['unix'] = unix_rules
+
         elif RE_PROFILE_CHANGE_HAT.search(line):
             matches = RE_PROFILE_CHANGE_HAT.search(line).groups()
 
@@ -3220,6 +3243,10 @@ def parse_pivot_root_rule(line):
     # XXX Do real parsing here
     return aarules.Raw_Pivot_Root_Rule(line)
 
+def parse_unix_rule(line):
+    # XXX Do real parsing here
+    return aarules.Raw_Unix_Rule(line)
+
 def separate_vars(vs):
     """Returns a list of all the values for a variable"""
     data = []
Index: b/utils/apparmor/rules.py
===================================================================
--- a/utils/apparmor/rules.py
+++ b/utils/apparmor/rules.py
@@ -44,6 +44,18 @@ class DBUS_Rule(object):
         out += ','
         return out
 
+class _Raw_Rule(object):
+    audit = False
+    deny = False
+
+    def __init__(self, rule):
+        self.rule = rule
+
+    def serialize(self):
+        return "%s%s%s" % ('audit ' if self.audit else '',
+                           'deny '  if self.deny else '',
+                           self.rule)
+
 class Raw_DBUS_Rule(object):
     audit = False
     deny = False
@@ -103,3 +115,6 @@ class Raw_Pivot_Root_Rule(object):
         return "%s%s%s" % ('audit ' if self.audit else '',
                            'deny '  if self.deny else '',
                            self.rule)
+
+class Raw_Unix_Rule(_Raw_Rule):
+    pass
Index: b/utils/test/test-regex_matches.py
===================================================================
--- a/utils/test/test-regex_matches.py
+++ b/utils/test/test-regex_matches.py
@@ -58,6 +58,12 @@ regex_has_comma_testcases = [
     ('pivot_root /old new%s', 'pivot_root with new'),
     ('pivot_root /old /new -> child%s', 'pivot_root with child'),
 
+    ('unix%s', 'bare unix'),
+    ('unix create%s', 'simple unix'),
+    ('peer=(addr=@abad1dea,label=a_profile) %s ', 'peer parens and comma'),
+    ('type=stream%s', 'unix type'),
+    ('unix (connect, receive, send)%s', 'unix perms'),
+
     # the following fail due to inadequacies in the regex
     # ('dbus (r, w, %s', 'incomplete dbus action'),
     # ('member="{Hello,AddMatch,RemoveMatch, %s', 'incomplete {} regex'),  # also invalid policy
@@ -334,6 +340,31 @@ class AARegexPivotRoot(unittest.TestCase
         ('pivot_rootbeer /new, # comment', False),
     ]
 
+class AARegexUnix(unittest.TestCase):
+    '''Tests for RE_PROFILE_UNIX'''
+
+    def setUp(self):
+        self.regex = aa.RE_PROFILE_UNIX
+
+    tests = [
+        ('   unix,', (None, None, 'unix,', None)),
+        ('   audit unix,', ('audit', None, 'unix,', None)),
+        ('   unix accept,', (None, None, 'unix accept,', None)),
+        ('   allow unix connect,', (None, 'allow', 'unix connect,', None)),
+        ('   audit allow unix bind,', ('audit', 'allow', 'unix bind,', None)),
+        ('   deny unix bind,', (None, 'deny', 'unix bind,', None)),
+        ('unix peer=(label=@{profile_name}),',
+         (None, None, 'unix peer=(label=@{profile_name}),', None)),
+        ('unix (receive) peer=(label=unconfined),',
+         (None, None, 'unix (receive) peer=(label=unconfined),', None)),
+        (' unix (getattr, shutdown) peer=(addr=none),',
+         (None, None, 'unix (getattr, shutdown) peer=(addr=none),', None)),
+        ('unix (connect, receive, send) type=stream peer=(label=unconfined,addr="@/tmp/dbus-*"),',
+         (None, None, 'unix (connect, receive, send) type=stream peer=(label=unconfined,addr="@/tmp/dbus-*"),', None)),
+        ('unixlike', False),
+        ('deny unixlike,', False),
+    ]
+
 if __name__ == '__main__':
     verbosity = 2
 
@@ -345,7 +376,7 @@ if __name__ == '__main__':
     test_suite.addTest(unittest.TestLoader().loadTestsFromTestCase(AARegexSplitComment))
 
     for tests in (AARegexCapability, AARegexPath, AARegexBareFile,
-                  AARegexDbus, AARegexMount,
+                  AARegexDbus, AARegexMount, AARegexUnix,
                   AARegexSignal, AARegexPtrace, AARegexPivotRoot):
         setup_regex_tests(tests)
         test_suite.addTest(unittest.TestLoader().loadTestsFromTestCase(tests))

-- 
Steve Beattie
<sbeattie at ubuntu.com>
http://NxNW.org/~steve/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <https://lists.ubuntu.com/archives/apparmor/attachments/20140827/d25dcc70/attachment-0001.pgp>


More information about the AppArmor mailing list