2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-31 14:25:52 +00:00

severity: replace load_variables() with set_variables()

Add set_variables() to severity.py to set the variables for severity
rating. It typically gets the data from the get_all_merged_variables()
result.

This replaces the slightly broken load_variables() that parsed profile
files for variables. (For example, parsing "@{foo} = /bar" resulted
in a variable name "@{foo} " with trailing space.)

Also adjust aa.py and the severity tests to use set_variables() (with
get_all_merged_variables()) instead of load_variables().

This also re-adds the checks that were removed in the "Store variables
in active_profiles (ProfileList)" commit earlier, while still fixing
lp:1331856.

With this change, unload_variables() becomes useless (the variables get
overwritten in set_variables() anyway), drop it and its calls.

Note that load_variables() silently ignored non-existing files while the
get_all_merged_variables() call only works for existing files that are
known to active_profiles. Since the input of ask_the_questions() and
ask_exec() comes from log_dict (= audit.log or a profile to merge), add
a check if that profile actually exists in the set of active profiles.

Also adjust the severity tests to use set_variables().

Finally, drop the tests that check for handling non-existing include
files, redefining and adding to non-existing variables - all these
things get now handled in include_list_recursive() and
get_all_merged_variables() and their tests.

Fixes: https://bugs.launchpad.net/apparmor/+bug/1331856
This commit is contained in:
Christian Boltz
2020-05-23 15:40:03 +02:00
parent 7451c341a6
commit 7d86bf9fe2
4 changed files with 27 additions and 80 deletions

View File

@@ -852,8 +852,12 @@ def ask_exec(hashlog):
# #
parent_uses_ld_xxx = check_for_LD_XXX(profile) parent_uses_ld_xxx = check_for_LD_XXX(profile)
sev_db.unload_variables() prof_filename = get_profile_filename_from_profile_name(profile)
sev_db.load_variables(get_profile_filename_from_profile_name(profile, True)) if prof_filename and active_profiles.files.get(prof_filename):
sev_db.set_variables(active_profiles.get_all_merged_variables(prof_filename, include_list_recursive(active_profiles.files[prof_filename]), profile_dir))
else:
sev_db.set_variables( {} )
severity = sev_db.rank_path(exec_target, 'x') severity = sev_db.rank_path(exec_target, 'x')
# Prompt portion starts # Prompt portion starts
@@ -1044,8 +1048,11 @@ def ask_the_questions(log_dict):
raise AppArmorBug(_('Invalid mode found: %s') % aamode) raise AppArmorBug(_('Invalid mode found: %s') % aamode)
for profile in sorted(log_dict[aamode].keys()): for profile in sorted(log_dict[aamode].keys()):
sev_db.unload_variables() prof_filename = get_profile_filename_from_profile_name(profile)
sev_db.load_variables(get_profile_filename_from_profile_name(profile, True)) if prof_filename and active_profiles.files.get(prof_filename):
sev_db.set_variables(active_profiles.get_all_merged_variables(prof_filename, include_list_recursive(active_profiles.files[prof_filename]), profile_dir))
else:
sev_db.set_variables( {} )
# Sorted list of hats with the profile name coming first # Sorted list of hats with the profile name coming first
hats = list(filter(lambda key: key != profile, sorted(log_dict[aamode][profile].keys()))) hats = list(filter(lambda key: key != profile, sorted(log_dict[aamode][profile].keys())))

View File

@@ -12,10 +12,8 @@
# #
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
from __future__ import with_statement from __future__ import with_statement
import os
import re import re
from apparmor.common import AppArmorException, open_file_read, warn, convert_regexp # , msg, error, debug from apparmor.common import AppArmorException, open_file_read, warn, convert_regexp # , msg, error, debug
from apparmor.regex import re_match_include
class Severity(object): class Severity(object):
def __init__(self, dbname=None, default_rank=10): def __init__(self, dbname=None, default_rank=10):
@@ -176,37 +174,6 @@ class Severity(object):
replacement = replacement[:-1] replacement = replacement[:-1]
return resource.replace(variable, replacement) return resource.replace(variable, replacement)
def load_variables(self, prof_path): def set_variables(self, vars):
"""Loads the variables for the given profile""" ''' Set the profile variables to use for rating the severity '''
if os.path.isfile(prof_path): self.severity['VARIABLES'] = vars
with open_file_read(prof_path) as f_in:
for line in f_in:
line = line.strip()
# If any includes, load variables from them first
match = re_match_include(line)
if match:
new_path = match
if not new_path.startswith('/'):
new_path = self.PROF_DIR + '/' + match
self.load_variables(new_path)
else:
# Remove any comments
if '#' in line:
line = line.split('#')[0].rstrip()
# Expected format is @{Variable} = value1 value2 ..
if line.startswith('@') and '=' in line:
if '+=' in line:
line = line.split('+=')
try:
self.severity['VARIABLES'][line[0]] += [i.strip('"') for i in line[1].split()]
except KeyError:
raise AppArmorException("Variable %s was not previously declared, but is being assigned additional value in file: %s" % (line[0], prof_path))
else:
line = line.split('=')
if line[0] in self.severity['VARIABLES'].keys():
raise AppArmorException("Variable %s was previously declared in file: %s" % (line[0], prof_path))
self.severity['VARIABLES'][line[0]] = [i.strip('"') for i in line[1].split()]
def unload_variables(self):
"""Clears all loaded variables"""
self.severity['VARIABLES'] = dict()

View File

@@ -355,6 +355,10 @@ class AaTest_get_all_merged_variables(AATest):
with self.assertRaises(AppArmorException): with self.assertRaises(AppArmorException):
apparmor.aa.active_profiles.get_all_merged_variables(os.path.join(self.profile_dir, 'usr.sbin.dnsmasq'), apparmor.aa.include_list_recursive(apparmor.aa.active_profiles.files[prof_filename]), self.profile_dir) apparmor.aa.active_profiles.get_all_merged_variables(os.path.join(self.profile_dir, 'usr.sbin.dnsmasq'), apparmor.aa.include_list_recursive(apparmor.aa.active_profiles.files[prof_filename]), self.profile_dir)
def test_vars_from_nonexisting_profile(self):
with self.assertRaises(AppArmorBug):
apparmor.aa.active_profiles.get_all_merged_variables(os.path.join(self.profile_dir, 'file.not.found'), list(), self.profile_dir)
setup_aa(apparmor.aa) setup_aa(apparmor.aa)
setup_all_loops(__name__) setup_all_loops(__name__)

View File

@@ -75,32 +75,6 @@ class SeverityTestCap(SeverityBaseTest):
class SeverityVarsTest(SeverityBaseTest): class SeverityVarsTest(SeverityBaseTest):
VARIABLE_DEFINITIONS = '''
@{HOME}=@{HOMEDIRS}/*/ /root/
@{HOMEDIRS}=/home/
# add another path to @{HOMEDIRS}
@{HOMEDIRS}+=/storage/
@{multiarch}=*-linux-gnu*
@{TFTP_DIR}=/var/tftp /srv/tftpboot
@{PROC}=/proc/
@{pid}={[1-9],[1-9][0-9],[1-9][0-9][0-9],[1-9][0-9][0-9][0-9],[1-9][0-9][0-9][0-9][0-9],[1-9][0-9][0-9][0-9][0-9][0-9]}
@{tid}=@{pid}
@{pids}=@{pid}
@{somepaths}=/home/foo/downloads @{HOMEDIRS}/foo/.ssh/
'''
def _init_tunables(self, content=''):
if not content:
content = self.VARIABLE_DEFINITIONS
self.rules_file = self.writeTmpfile('tunables', content)
self.sev_db.load_variables(self.rules_file)
def AATeardown(self):
self.sev_db.unload_variables()
tests = [ tests = [
(['@{PROC}/sys/vm/overcommit_memory', 'r'], 6), (['@{PROC}/sys/vm/overcommit_memory', 'r'], 6),
(['@{HOME}/sys/@{PROC}/overcommit_memory', 'r'], 4), (['@{HOME}/sys/@{PROC}/overcommit_memory', 'r'], 4),
@@ -110,22 +84,17 @@ class SeverityVarsTest(SeverityBaseTest):
] ]
def _run_test(self, params, expected): def _run_test(self, params, expected):
self._init_tunables() vars = {
'@{HOME}': {'@{HOMEDIRS}/*/', '/root/'},
'@{HOMEDIRS}': {'/home/', '/storage/'},
'@{multiarch}': {'*-linux-gnu*'},
'@{TFTP_DIR}': {'/var/tftp /srv/tftpboot'},
'@{PROC}': {'/proc/'},
'@{somepaths}': {'/home/foo/downloads', '@{HOMEDIRS}/foo/.ssh/'},
}
self.sev_db.set_variables(vars)
self._simple_severity_w_perm(params[0], params[1], expected) self._simple_severity_w_perm(params[0], params[1], expected)
def test_include(self):
self._init_tunables('#include <file/not/found>') # including non-existing files doesn't raise an exception
self.assertTrue(True) # this test only makes sure that loading the tunables file works
def test_invalid_variable_add(self):
with self.assertRaises(AppArmorException):
self._init_tunables('@{invalid} += /home/')
def test_invalid_variable_double_definition(self):
with self.assertRaises(AppArmorException):
self._init_tunables('@{foo} = /home/\n@{foo} = /root/')
class SeverityDBTest(AATest): class SeverityDBTest(AATest):
def _test_db(self, contents): def _test_db(self, contents):
self.db_file = self.writeTmpfile('severity.db', contents) self.db_file = self.writeTmpfile('severity.db', contents)