diff options
author | Jake Hunsaker <jhunsake@redhat.com> | 2021-01-06 12:51:38 -0500 |
---|---|---|
committer | Jake Hunsaker <jhunsake@redhat.com> | 2021-01-13 13:12:27 -0500 |
commit | 0f74186752d85d80006187261e9bdb8b104a05fe (patch) | |
tree | dbb8534d027023fc521122135eeaac9f564fe961 | |
parent | 5fb859f52a5a77657d509c7f4d3590fdca694931 (diff) | |
download | sos-0f74186752d85d80006187261e9bdb8b104a05fe.tar.gz |
[Policy] Add policy-controlled forbidden paths
This adds policy-controlled forbidden path checking, which
should be the final part of implementing "global" forbidden paths. With
this commit, policies may now add paths and glob matches for paths which
should never be collected in any plugin.
Combined with plugin-defined paths and user-defined paths already
available, plugins should now be able to be properly restricted from
sensitive collections.
Note that the way this is implemented is that policies that define the
`set_forbidden_paths()` classmethod *extend* this forbidden list as it
is built from the subclass(es) that also define one. This way,
"top-level" policies do not need to maintain independent copies of
entire trees of paths just to add a few specific additional ones that
are not forbidden within other policies.
This initial commit adds paths that are either very well-known to be
ones we should avoid, or are paths that have previously been part of
reported issues where these paths/files should not be collected.
Closes: #316
Closes: #796
Closes: #919
Closes: #1316
Resolves: #2360
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
-rw-r--r-- | sos/policies/__init__.py | 28 | ||||
-rw-r--r-- | sos/policies/distros/__init__.py | 7 | ||||
-rw-r--r-- | sos/report/plugins/__init__.py | 9 | ||||
-rw-r--r-- | tests/policy_tests.py | 16 |
4 files changed, 60 insertions, 0 deletions
diff --git a/sos/policies/__init__.py b/sos/policies/__init__.py index 00243a91..a123926d 100644 --- a/sos/policies/__init__.py +++ b/sos/policies/__init__.py @@ -141,6 +141,34 @@ any third party. """ return False + @property + def forbidden_paths(self): + """This property is used to determine the list of forbidden paths + set by the policy. Note that this property will construct a + *cumulative* list based on all subclasses of a given policy. + + :returns: All patterns of policy forbidden paths + :rtype: ``list`` + """ + if not hasattr(self, '_forbidden_paths'): + self._forbidden_paths = [] + for cls in self.__class__.__mro__: + if hasattr(cls, 'set_forbidden_paths'): + self._forbidden_paths.extend(cls.set_forbidden_paths()) + return list(set(self._forbidden_paths)) + + @classmethod + def set_forbidden_paths(cls): + """Use this to *append* policy-specifc forbidden paths that apply to + all plugins. Setting this classmethod on an invidual policy will *not* + override subclass-specific paths + """ + return [ + '*.pyc', + '*.pyo', + '*.swp' + ] + def in_container(self): """Are we running inside a container? diff --git a/sos/policies/distros/__init__.py b/sos/policies/distros/__init__.py index c97cc1a5..c5fb4801 100644 --- a/sos/policies/distros/__init__.py +++ b/sos/policies/distros/__init__.py @@ -94,6 +94,13 @@ class LinuxPolicy(Policy): idx = list(self.runtimes.keys()) self.runtimes['default'] = self.runtimes[idx[0]] + @classmethod + def set_forbidden_paths(cls): + return [ + '/etc/passwd', + '/etc/shadow' + ] + def get_preferred_hash_name(self): if self._preferred_hash_name: diff --git a/sos/report/plugins/__init__.py b/sos/report/plugins/__init__.py index 1527caea..3ae6507d 100644 --- a/sos/report/plugins/__init__.py +++ b/sos/report/plugins/__init__.py @@ -1082,6 +1082,11 @@ class Plugin(object): def _is_forbidden_path(self, path): return _path_in_path_list(path, self.forbidden_paths) + def _is_policy_forbidden_path(self, path): + return any([ + fnmatch.fnmatch(path, fp) for fp in self.policy.forbidden_paths + ]) + def _is_skipped_path(self, path): """Check if the given path matches a user-provided specification to ignore collection of via the ``--skip-files`` option @@ -1441,6 +1446,10 @@ class Plugin(object): if self._is_forbidden_path(_file): self._log_debug("skipping forbidden path '%s'" % _file) continue + if self._is_policy_forbidden_path(_file): + self._log_debug("skipping policy forbidden path '%s'" + % _file) + continue if self._is_skipped_path(_file): self._log_debug("skipping excluded path '%s'" % _file) continue diff --git a/tests/policy_tests.py b/tests/policy_tests.py index 4b248b70..6d0c42b9 100644 --- a/tests/policy_tests.py +++ b/tests/policy_tests.py @@ -8,6 +8,7 @@ import unittest from sos.policies import Policy, import_policy +from sos.policies.distros import LinuxPolicy from sos.policies.package_managers import PackageManager from sos.report.plugins import (Plugin, IndependentPlugin, RedHatPlugin, DebianPlugin) @@ -17,6 +18,14 @@ class FauxPolicy(Policy): distro = "Faux" +class FauxLinuxPolicy(LinuxPolicy): + distro = "FauxLinux" + + @classmethod + def set_forbidden_paths(cls): + return ['/etc/secret'] + + class FauxPlugin(Plugin, IndependentPlugin): pass @@ -31,12 +40,19 @@ class FauxDebianPlugin(Plugin, DebianPlugin): class PolicyTests(unittest.TestCase): + def test_independent_only(self): p = FauxPolicy() p.valid_subclasses = [] self.assertTrue(p.validate_plugin(FauxPlugin)) + def test_forbidden_paths_building(self): + p = FauxLinuxPolicy(probe_runtime=False) + self.assertTrue('*.pyc' in p.forbidden_paths) + self.assertTrue('/etc/passwd' in p.forbidden_paths) + self.assertTrue('/etc/secret' in p.forbidden_paths) + def test_redhat(self): p = FauxPolicy() p.valid_subclasses = [RedHatPlugin] |