[apparmor] [patch] [23/38] Add get_file_perms to aa.py

Christian Boltz apparmor at cboltz.de
Fri Aug 12 21:00:30 UTC 2016


Hello,

get_file_perms() collects the existing permissions for a file from
various rules (exact matches, wildcards) in the main profile and the
included abstractions.

It will be used to get displaying the current permissions back, and also
to propose rules with merged permissions (next patch).

Also add some tests to make sure it does what it promises ;-)



[ 23-get-existing-file-permissions.diff ]

=== modified file ./utils/apparmor/aa.py
--- utils/apparmor/aa.py	2016-05-09 23:11:08.615393607 +0200
+++ utils/apparmor/aa.py	2016-05-09 23:11:55.483124584 +0200
@@ -3791,6 +3796,40 @@
 
     return False
 
+def get_file_perms(profile, path, audit, deny):
+    '''get the current permissions for the given path'''
+
+    perms = profile['file'].get_perms_for_path(path, audit, deny)
+
+    includelist = list(profile['include'].keys())
+    checked = []
+
+    while includelist:
+        incname = includelist.pop(0)
+
+        if incname in checked:
+            continue
+        checked.append(incname)
+
+        if os.path.isdir(profile_dir + '/' + incname):
+            includelist += include_dir_filelist(profile_dir, incname)
+        else:
+            incperms = include[incname][incname]
['file'].get_perms_for_path(path, audit, deny)
+
+            for allow_or_deny in ['allow', 'deny']:
+                for owner_or_all in ['all', 'owner']:
+                    for perm in incperms[allow_or_deny][owner_or_all]:
+                        perms[allow_or_deny][owner_or_all].add(perm)
+
+            for incpath in incperms['paths']:
+                perms['paths'].add(incpath)
+
+            for childinc in include[incname][incname]
['include'].keys():
+                if childinc not in checked:
+                    includelist += [childinc]
+
+    return perms
+
 def reload_base(bin_path):
     if not check_for_apparmor():
         return None
=== modified file ./utils/test/test-aa.py
--- utils/test/test-aa.py	2016-05-09 23:11:08.615393607 +0200
+++ utils/test/test-aa.py	2016-05-09 23:13:25.334609141 +0200
@@ -20,8 +20,9 @@
 from apparmor.aa import (check_for_apparmor, get_output, get_reqs, 
get_interpreter_and_abstraction, create_new_profile,
      get_profile_flags, set_profile_flags, is_skippable_file, 
is_skippable_dir,
      parse_profile_start, parse_profile_data, separate_vars, 
store_list_var, write_header,
-     var_transform, serialize_parse_profile_start)
+     var_transform, serialize_parse_profile_start, get_file_perms)
 from apparmor.common import AppArmorException, AppArmorBug
+from apparmor.rule.file import FileRule
 
 class AaTestWithTempdir(AATest):
     def AASetup(self):
@@ -722,7 +723,70 @@
             # 'correct' is always True in the code that uses 
serialize_parse_profile_start() (set some lines above the function call)
             serialize_parse_profile_start(line, 'somefile', 1, profile, 
hat, prof_data_profile, prof_data_external, True)
 
+class AaTest_get_file_perms_1(AATest):
+    tests = [
+        ('/usr/share/common-licenses/foo/bar',      {'allow': {'all': 
set(),            'owner': {'w'}  }, 'deny': {'all':set(),    'owner': 
set()},    'paths': {'/usr/share/common-licenses/**'}  }),
+        ('/dev/null',                               {'allow': {'all': 
{'r', 'w', 'k'},  'owner': set()  }, 'deny': {'all':set(),    'owner': 
set()},    'paths': {'/dev/null'}                      }),
+        ('/foo/bar',                                {'allow': {'all': 
{'r', 'w'},       'owner': set()  }, 'deny': {'all':set(),    'owner': 
set()},    'paths': {'/foo/bar'}                       }),  # exec perms 
not included
+        ('/no/thing',                               {'allow': {'all': 
set(),            'owner': set()  }, 'deny': {'all':set(),    'owner': 
set()},    'paths': set()                              }),
+        ('/usr/lib/ispell/',                        {'allow': {'all': 
set(),            'owner': set()  }, 'deny': {'all':set(),    'owner': 
set()},    'paths': set()                              }),
+        ('/usr/lib/aspell/*.so',                    {'allow': {'all': 
set(),            'owner': set()  }, 'deny': {'all':set(),    'owner': 
set()},    'paths': set()                              }),
+    ]
+
+    def _run_test(self, params, expected):
+        self.createTmpdir()
+
+        #copy the local profiles to the test directory
+        self.profile_dir = '%s/profiles' % self.tmpdir
+        shutil.copytree('../../profiles/apparmor.d/', self.profile_dir, 
symlinks=True)
+
+        profile = apparmor.aa.profile_storage('/test', '/test', 'test-
aa.py')
+
+        # simple profile without any includes
+        profile['file'].add(FileRule.parse('owner /usr/share/common-
licenses/**  w,'))
+        profile['file'].add(FileRule.parse('/dev/null rwk,'))
+        profile['file'].add(FileRule.parse('/foo/bar rwix,'))
+
+        perms = get_file_perms(profile, params, False, False)  # only 
testing with audit and deny = False
+        self.assertEqual(perms, expected)
+
+class AaTest_get_file_perms_2(AATest):
+    tests = [
+        ('/usr/share/common-licenses/foo/bar',      {'allow': {'all': 
{'r'},            'owner': {'w'}  }, 'deny': {'all':set(),    'owner': 
set()},    'paths': {'/usr/share/common-licenses/**'}              }),
+        ('/dev/null',                               {'allow': {'all': 
{'r', 'w', 'k'},  'owner': set()  }, 'deny': {'all':set(),    'owner': 
set()},    'paths': {'/dev/null'}                                  }),
+        ('/foo/bar',                                {'allow': {'all': 
{'r', 'w'},       'owner': set()  }, 'deny': {'all':set(),    'owner': 
set()},    'paths': {'/foo/bar'}                                   }),  
# exec perms not included
+        ('/no/thing',                               {'allow': {'all': 
set(),            'owner': set()  }, 'deny': {'all':set(),    'owner': 
set()},    'paths': set()                                          }),
+        ('/usr/lib/ispell/',                        {'allow': {'all': 
{'r'},            'owner': set()  }, 'deny': {'all':set(),    'owner': 
set()},    'paths': {'/usr/lib/ispell/', '/usr/lib{,32,64}/**'}    }),  
# from abstractions/enchant
+        ('/usr/lib/aspell/*.so',                    {'allow': {'all': 
{'m', 'r'},       'owner': set()  }, 'deny': {'all':set(),    'owner': 
set()},    'paths': {'/usr/lib/aspell/*', '/usr/lib/aspell/*.so', '/usr/
lib{,32,64}/**'} }),  # from abstractions/aspell via abstractions/
enchant
+    ]
+
+    def _run_test(self, params, expected):
+        self.createTmpdir()
+
+        #copy the local profiles to the test directory
+        self.profile_dir = '%s/profiles' % self.tmpdir
+        shutil.copytree('../../profiles/apparmor.d/', self.profile_dir, 
symlinks=True)
+
+        # load the abstractions we need in the test
+        apparmor.aa.profiledir = self.profile_dir
+        apparmor.aa.load_include('abstractions/base')
+        apparmor.aa.load_include('abstractions/bash')
+        apparmor.aa.load_include('abstractions/enchant')
+        apparmor.aa.load_include('abstractions/aspell')
+
+        profile = apparmor.aa.profile_storage('/test', '/test', 'test-
aa.py')
+        profile['include']['abstractions/base'] = True
+        profile['include']['abstractions/bash'] = True
+        profile['include']['abstractions/enchant'] = True  # includes 
abstractions/aspell
+
+        profile['file'].add(FileRule.parse('owner /usr/share/common-
licenses/**  w,'))
+        profile['file'].add(FileRule.parse('/dev/null rwk,'))
+        profile['file'].add(FileRule.parse('/foo/bar rwix,'))
+
+        perms = get_file_perms(profile, params, False, False)  # only 
testing with audit and deny = False
+        self.assertEqual(perms, expected)
+
 
 setup_all_loops(__name__)
 if __name__ == '__main__':




Regards,

Christian Boltz
-- 
http://portal.suse.com/sdb/de/1997/09/maddin_kopieren.html
Der Artikel wird demnächst 7, sollte also in die zweite Klasse
Grundschule gehen, sobald die Ferien vorbei sind...
[Michael Behrens in suse-linux]
-------------- 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/d05511d5/attachment.pgp>


More information about the AppArmor mailing list