2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-09-03 07:45:50 +00:00

IncludeRule: add get_full_paths()

This function returns a list of paths for an include rule. This can be
- a single path if the include file is a file and exists
- a single path if the include file doesn't exist, but doesn't have
  'if exists' (this will cause a 'file not found' error when used)
- a list of paths if the include is a directory
- an empty list if the rule has 'if exists' and the file doesn't exist

Also add some tests for get_full_paths()
This commit is contained in:
Christian Boltz
2020-05-16 22:36:05 +02:00
parent d799195e0a
commit f3f597ff0b
2 changed files with 73 additions and 2 deletions

View File

@@ -13,8 +13,9 @@
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
from apparmor.regex import RE_INCLUDE, re_match_include_parse from apparmor.regex import RE_INCLUDE, re_match_include_parse
from apparmor.common import AppArmorBug, AppArmorException, type_is_str from apparmor.common import AppArmorBug, AppArmorException, is_skippable_file, type_is_str
from apparmor.rule import BaseRule, BaseRuleset, parse_comment from apparmor.rule import BaseRule, BaseRuleset, parse_comment
import os
# setup module translations # setup module translations
from apparmor.translations import init_translation from apparmor.translations import init_translation
@@ -124,6 +125,34 @@ class IncludeRule(BaseRule):
_('Include'), self.get_clean(), _('Include'), self.get_clean(),
] ]
def get_full_paths(self, profile_dir):
''' get list of full paths of an include (can contain multiple paths if self.path is a directory) '''
# currently this section is based on aa.py get_include_path() (with variable names changed)
# TODO: improve/fix logic to honor magic vs. quoted include paths
if self.path.startswith('/'):
full_path = self.path
else:
full_path = os.path.join(profile_dir, self.path)
files = []
if os.path.isdir(full_path):
for path in os.listdir(full_path):
if is_skippable_file(path):
continue
file_name = os.path.join(full_path, path)
if os.path.isfile(file_name): # only add files, but not subdirectories etc.
files.append(file_name)
elif os.path.exists(full_path):
files.append(full_path)
elif self.ifexists == False:
files.append(full_path) # add full_path even if it doesn't exist on disk. Might cause a 'file not found' error later.
return files
class IncludeRuleset(BaseRuleset): class IncludeRuleset(BaseRuleset):
'''Class to handle and store a collection of include rules''' '''Class to handle and store a collection of include rules'''

View File

@@ -15,7 +15,10 @@
import unittest import unittest
from collections import namedtuple from collections import namedtuple
from common_test import AATest, setup_all_loops from common_test import AATest, setup_all_loops, write_file
import os
import shutil
from apparmor.rule.include import IncludeRule, IncludeRuleset from apparmor.rule.include import IncludeRule, IncludeRuleset
#from apparmor.rule import BaseRule #from apparmor.rule import BaseRule
@@ -336,6 +339,45 @@ class IncludeLogprofHeaderTest(AATest):
obj = IncludeRule._parse(params) obj = IncludeRule._parse(params)
self.assertEqual(obj.logprof_header(), expected) self.assertEqual(obj.logprof_header(), expected)
class IncludeFullPathsTest(AATest):
def AASetup(self):
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)
inc_dir = os.path.join(self.profile_dir, 'abstractions/inc.d')
os.mkdir(inc_dir, 0o755)
write_file(inc_dir, 'incfoo', '/incfoo r,')
write_file(inc_dir, 'incbar', '/incbar r,')
write_file(inc_dir, 'README', '# README') # gets skipped
sub_dir = os.path.join(self.profile_dir, 'abstractions/inc.d/subdir') # gets skipped
os.mkdir(sub_dir, 0o755)
empty_dir = os.path.join(self.profile_dir, 'abstractions/empty.d')
os.mkdir(empty_dir, 0o755)
tests = [
# @@ will be replaced with self.profile_dir
('include <abstractions/base>', ['@@/abstractions/base'] ),
# ('include "foo"', ['@@/foo'] ), # TODO: adjust logic to honor quoted vs. magic paths (and allow quoted relative paths in re_match_include_parse())
('include "/foo/bar"', ['/foo/bar'] ),
('include <abstractions/inc.d>', ['@@/abstractions/inc.d/incfoo', '@@/abstractions/inc.d/incbar'] ),
('include <abstractions/empty.d>', [] ),
('include <abstractions/not_found>', ['@@/abstractions/not_found'] ),
('include if exists <abstractions/not_found>', [] ),
]
def _run_test(self, params, expected):
exp2 = []
for path in expected:
exp2.append(path.replace('@@', self.profile_dir))
obj = IncludeRule._parse(params)
self.assertEqual(obj.get_full_paths(self.profile_dir), exp2)
## --- tests for IncludeRuleset --- # ## --- tests for IncludeRuleset --- #
class IncludeRulesTest(AATest): class IncludeRulesTest(AATest):