[apparmor] [patch] [13/38] Add ANY_EXEC to FileRule

Christian Boltz apparmor at cboltz.de
Fri Aug 12 20:54:09 UTC 2016


Hello,

aa-logprof needs to check if an exec rule for a given path exists.

This patch adds a __FileAnyExec class to FileRule, as well as ANY_EXEC
(which should be used externally, similar to ALL), and adjusts several
checks to allow it as a special execute mode.

This will allow to use is_covered() (or aa.py is_known_rule()) to find
out if execute is permitted, which replaces aa.py profile_known_exec()
in one of the following patches.

As usual, also add some tests.


[ 13-FileRule-add-ANY_EXEC.diff ]

=== modified file ./utils/apparmor/rule/file.py
--- utils/apparmor/rule/file.py	2016-02-21 15:43:58.009985520 +0100
+++ utils/apparmor/rule/file.py	2016-02-21 16:05:39.673508607 +0100
@@ -35,8 +35,11 @@
     # should reference the class field FileRule.ALL
     class __FileAll(object):
         pass
+    class __FileAnyExec(object):
+        pass
 
     ALL = __FileAll
+    ANY_EXEC = __FileAnyExec
 
     rule_name = 'file'
 
@@ -76,6 +79,8 @@
 
         if exec_perms is None:
             self.exec_perms = None
+        elif exec_perms == self.ANY_EXEC:
+            self.exec_perms = exec_perms
         elif type_is_str(exec_perms):
             if deny:
                 if exec_perms != 'x':
@@ -211,6 +216,8 @@
             if perm in self.perms:
                 perm_string = perm_string + perm
 
+        if self.exec_perms == self.ANY_EXEC:
+            raise AppArmorBug("FileRule.ANY_EXEC can't be used for actual rules")
         if self.exec_perms:
             perm_string = perm_string + self.exec_perms
 
@@ -235,12 +242,14 @@
             return False
 
         # TODO: handle fallback modes?
-        if other_rule.exec_perms and self.exec_perms != other_rule.exec_perms:
+        if other_rule.exec_perms == self.ANY_EXEC and self.exec_perms:
+            pass  # avoid hitting the 'elif' branch
+        elif other_rule.exec_perms and self.exec_perms != other_rule.exec_perms:
             return False
 
-        # check exec_mode and target only if other_rule contains exec_perms or link permissions
+        # check exec_mode and target only if other_rule contains exec_perms (except ANY_EXEC) or link permissions
         # (for mrwk permissions, the target is ignored anyway)
-        if other_rule.exec_perms or (other_rule.perms and 'l' in other_rule.perms):
+        if (other_rule.exec_perms and other_rule.exec_perms != self.ANY_EXEC) or (other_rule.perms and 'l' in other_rule.perms):
             if not self._is_covered_aare(self.target,   self.all_targets,       other_rule.target,      other_rule.all_targets,         'target'):
                 return False
 
=== modified file ./utils/test/test-file.py
--- utils/test/test-file.py	2016-02-21 15:43:58.009985520 +0100
+++ utils/test/test-file.py	2016-02-21 16:05:39.673508607 +0100
@@ -379,6 +379,10 @@
        self.assertEqual(expected, obj.get_clean(2), 'unexpected clean rule')
        self.assertEqual(expected, obj.get_raw(2), 'unexpected raw rule')
 
+    def test_write_any_exec(self):
+        obj   = FileRule( '/foo',         'rw',   FileRule.ANY_EXEC,'/bar',    False,  False,          False)
+        with self.assertRaises(AppArmorBug):
+            obj.get_clean()
 
 class FileCoveredTest(AATest):
     def _run_test(self, param, expected):@@ -603,8 +652,6 @@
@@ -584,6 +584,55 @@
         self.assertTrue(self.obj.is_equal(self.testobj, strict=False))
         self.assertFalse(self.obj.is_equal(self.testobj, strict=True))
 
+    def test_covered_anyperm_1(self):
+        self.obj       = FileRule( '/foo',         'rw',   None,       '/bar',         False,  False,          False)
+        self.testobj   = FileRule( '/foo',         'rw',   FileRule.ANY_EXEC, '/bar',   False,  False,          False)
+        self.assertFalse(self.obj.is_covered(self.testobj))
+        self.assertFalse(self.obj.is_equal(self.testobj, strict=False))
+        self.assertFalse(self.obj.is_equal(self.testobj, strict=True))
+
+    def test_covered_anyperm_2(self):
+        self.testobj   = FileRule( '/foo',         'rw',   FileRule.ANY_EXEC,'/bar',    False,  False,          False)
+        self.assertTrue(self.obj.is_covered(self.testobj))
+        self.assertFalse(self.obj.is_equal(self.testobj, strict=False))
+        self.assertFalse(self.obj.is_equal(self.testobj, strict=True))
+
+    def test_covered_anyperm_3(self):
+        # make sure a different exec target gets ignored with ANY_EXEC
+        self.testobj   = FileRule( '/foo',         'rw',   FileRule.ANY_EXEC, '/xyz',   False,  False,          False)
+        self.assertTrue(self.obj.is_covered(self.testobj))
+        self.assertFalse(self.obj.is_equal(self.testobj, strict=False))
+        self.assertFalse(self.obj.is_equal(self.testobj, strict=True))
+
+    def test_covered_anyperm_4(self):
+        # make sure a different exec target gets ignored with ANY_EXEC
+        self.testobj   = FileRule( '/foo',         'rw',   FileRule.ANY_EXEC, FileRule.ALL, False,  False,          False)
+        self.assertTrue(self.obj.is_covered(self.testobj))
+        self.assertFalse(self.obj.is_equal(self.testobj, strict=False))
+        self.assertFalse(self.obj.is_equal(self.testobj, strict=True))
+
+    def test_covered_anyperm_5(self):
+        # even with ANY_EXEC, a different link target causes a mismatch
+        self.testobj   = FileRule( '/foo',         'rwl',  FileRule.ANY_EXEC, '/xyz',   False,  False,          False)
+        self.assertFalse(self.obj.is_covered(self.testobj))
+        self.assertFalse(self.obj.is_equal(self.testobj, strict=False))
+        self.assertFalse(self.obj.is_equal(self.testobj, strict=True))
+
+    def test_covered_anyperm_6(self):
+        # even with ANY_EXEC, a different link target causes a mismatch
+        self.testobj   = FileRule( '/foo',         'rwl',  FileRule.ANY_EXEC, FileRule.ALL, False,  False,          False)
+        self.assertFalse(self.obj.is_covered(self.testobj))
+        self.assertFalse(self.obj.is_equal(self.testobj, strict=False))
+        self.assertFalse(self.obj.is_equal(self.testobj, strict=True))
+
+    def test_covered_anyperm_7(self):
+        self.obj       = FileRule( '/foo',         'rw',   'x',        '/bar',         False,  False,          False, deny=True)
+        self.testobj   = FileRule( '/foo',         'rw',   FileRule.ANY_EXEC,'/bar',    False,  False,          False)
+        self.assertFalse(self.obj.is_covered(self.testobj))
+        self.assertTrue(self.obj.is_covered(self.testobj, check_allow_deny=False))
+        self.assertFalse(self.obj.is_equal(self.testobj, strict=False))
+        self.assertFalse(self.obj.is_equal(self.testobj, strict=True))
+
     def test_borked_obj_is_covered_1(self):
         self.testobj.path = ''
 




Regards,

Christian Boltz
-- 
> If there is some software side way of knowing that...
In this case special hardware, called hammer will help ;-P
[>  Carlos E. R. and Cristian Rodríguez 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/08fc2d4e/attachment.pgp>


More information about the AppArmor mailing list