mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-01 14:55:10 +00:00
Replace existing_profiles & fix minitools for named profiles
Technical stuff first:
Replace existing_profiles (a dict with the filenames for both active and
inactive profiles) with active_profiles and extra_profiles which are
ProfileList()s and store the active profiles and those in the extra
directory separately. Thanks to ProfileList, now also the relation
between attachments and filenames is easily available.
Also replace all usage of existing_profiles with active_profiles and
extra_profiles, and adjust it to the ProfileList syntax everywhere.
With this change, several bugs in aa-complain and the other minitools
get fixed:
- aa-complain etc. never found profiles that have a profile name
(the attachment wasn't checked)
- even if the profile name was given as parameter to aa-complain, it
first did "which $parameter" so it never matched on named profiles
- profile names with alternations (without attachment specification)
also never matched because the old code didn't use AARE.
References: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=882047#92
(search for "As usual" ;-)
Just for completeness - the matching still doesn't honor/expand
variables in the profile name.
PR: https://gitlab.com/apparmor/apparmor/merge_requests/268
(cherry picked from commit 4d722f1839
)
Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
committed by
John Johansen
parent
848fbae814
commit
f997977e6b
@@ -1,7 +1,7 @@
|
|||||||
#! /usr/bin/python3
|
#! /usr/bin/python3
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
||||||
# Copyright (C) 2014-2017 Christian Boltz <apparmor@cboltz.de>
|
# Copyright (C) 2014-2018 Christian Boltz <apparmor@cboltz.de>
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of version 2 of the GNU General Public
|
# modify it under the terms of version 2 of the GNU General Public
|
||||||
@@ -57,7 +57,7 @@ def reset_aa():
|
|||||||
apparmor.aa.aa = apparmor.aa.hasher()
|
apparmor.aa.aa = apparmor.aa.hasher()
|
||||||
apparmor.aa.filelist = apparmor.aa.hasher()
|
apparmor.aa.filelist = apparmor.aa.hasher()
|
||||||
apparmor.aa.include = dict()
|
apparmor.aa.include = dict()
|
||||||
apparmor.aa.existing_profiles = apparmor.aa.hasher()
|
apparmor.aa.active_profiles = apparmor.aa.ProfileList()
|
||||||
apparmor.aa.original_aa = apparmor.aa.hasher()
|
apparmor.aa.original_aa = apparmor.aa.hasher()
|
||||||
|
|
||||||
def find_profiles_from_files(files):
|
def find_profiles_from_files(files):
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
||||||
# Copyright (C) 2014-2017 Christian Boltz <apparmor@cboltz.de>
|
# Copyright (C) 2014-2018 Christian Boltz <apparmor@cboltz.de>
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of version 2 of the GNU General Public
|
# modify it under the terms of version 2 of the GNU General Public
|
||||||
@@ -49,6 +49,8 @@ from apparmor.regex import (RE_PROFILE_START, RE_PROFILE_END, RE_PROFILE_LINK,
|
|||||||
RE_PROFILE_UNIX, RE_RULE_HAS_COMMA, RE_HAS_COMMENT_SPLIT,
|
RE_PROFILE_UNIX, RE_RULE_HAS_COMMA, RE_HAS_COMMENT_SPLIT,
|
||||||
strip_quotes, parse_profile_start_line, re_match_include )
|
strip_quotes, parse_profile_start_line, re_match_include )
|
||||||
|
|
||||||
|
from apparmor.profile_list import ProfileList
|
||||||
|
|
||||||
from apparmor.profile_storage import ProfileStorage, add_or_remove_flag, ruletypes, write_abi
|
from apparmor.profile_storage import ProfileStorage, add_or_remove_flag, ruletypes, write_abi
|
||||||
|
|
||||||
import apparmor.rules as aarules
|
import apparmor.rules as aarules
|
||||||
@@ -88,7 +90,8 @@ extra_profile_dir = None
|
|||||||
# To keep track of previously included profile fragments
|
# To keep track of previously included profile fragments
|
||||||
include = dict()
|
include = dict()
|
||||||
|
|
||||||
existing_profiles = dict()
|
active_profiles = ProfileList()
|
||||||
|
extra_profiles = ProfileList()
|
||||||
|
|
||||||
# To store the globs entered by users so they can be provided again
|
# To store the globs entered by users so they can be provided again
|
||||||
# format: user_globs['/foo*'] = AARE('/foo*')
|
# format: user_globs['/foo*'] = AARE('/foo*')
|
||||||
@@ -219,7 +222,7 @@ def find_executable(bin_path):
|
|||||||
def get_profile_filename_from_profile_name(profile, get_new=False):
|
def get_profile_filename_from_profile_name(profile, get_new=False):
|
||||||
"""Returns the full profile name for the given profile name"""
|
"""Returns the full profile name for the given profile name"""
|
||||||
|
|
||||||
filename = get_profile_filename_orig(profile)
|
filename = active_profiles.filename_from_profile_name(profile)
|
||||||
if filename:
|
if filename:
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
@@ -229,18 +232,13 @@ def get_profile_filename_from_profile_name(profile, get_new=False):
|
|||||||
def get_profile_filename_from_attachment(profile, get_new=False):
|
def get_profile_filename_from_attachment(profile, get_new=False):
|
||||||
"""Returns the full profile name for the given attachment"""
|
"""Returns the full profile name for the given attachment"""
|
||||||
|
|
||||||
filename = get_profile_filename_orig(profile)
|
filename = active_profiles.filename_from_attachment(profile)
|
||||||
if filename:
|
if filename:
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
if get_new:
|
if get_new:
|
||||||
return get_new_profile_filename(profile)
|
return get_new_profile_filename(profile)
|
||||||
|
|
||||||
def get_profile_filename_orig(profile):
|
|
||||||
"""Returns the full profile name"""
|
|
||||||
if existing_profiles.get(profile, False):
|
|
||||||
return existing_profiles[profile]
|
|
||||||
|
|
||||||
def get_new_profile_filename(profile):
|
def get_new_profile_filename(profile):
|
||||||
'''Compose filename for a new profile'''
|
'''Compose filename for a new profile'''
|
||||||
if profile.startswith('/'):
|
if profile.startswith('/'):
|
||||||
@@ -526,7 +524,8 @@ def get_profile(prof_name):
|
|||||||
profile_hash[uname]['profile'] = serialize_profile(inactive_profile[prof_name], prof_name, None)
|
profile_hash[uname]['profile'] = serialize_profile(inactive_profile[prof_name], prof_name, None)
|
||||||
profile_hash[uname]['profile_data'] = inactive_profile
|
profile_hash[uname]['profile_data'] = inactive_profile
|
||||||
|
|
||||||
existing_profiles.pop(prof_name) # remove profile filename from list to force storing in /etc/apparmor.d/ instead of extra_profile_dir
|
# no longer necessary after splitting active and extra profiles
|
||||||
|
# existing_profiles.pop(prof_name) # remove profile filename from list to force storing in /etc/apparmor.d/ instead of extra_profile_dir
|
||||||
|
|
||||||
# If no profiles in repo and no inactive profiles
|
# If no profiles in repo and no inactive profiles
|
||||||
if not profile_hash.keys():
|
if not profile_hash.keys():
|
||||||
@@ -714,15 +713,16 @@ def profile_exists(program):
|
|||||||
"""Returns True if profile exists, False otherwise"""
|
"""Returns True if profile exists, False otherwise"""
|
||||||
# Check cache of profiles
|
# Check cache of profiles
|
||||||
|
|
||||||
if existing_profiles.get(program, False):
|
if active_profiles.filename_from_attachment(program):
|
||||||
return True
|
return True
|
||||||
# Check the disk for profile
|
# Check the disk for profile
|
||||||
prof_path = get_profile_filename_from_attachment(program, True)
|
prof_path = get_profile_filename_from_attachment(program, True)
|
||||||
#print(prof_path)
|
#print(prof_path)
|
||||||
if os.path.isfile(prof_path):
|
if os.path.isfile(prof_path):
|
||||||
# Add to cache of profile
|
# Add to cache of profile
|
||||||
existing_profiles[program] = prof_path
|
raise AppArmorBug('Reached strange condition in profile_exists(), please open a bugreport!')
|
||||||
return True
|
# active_profiles[program] = prof_path
|
||||||
|
# return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def sync_profile():
|
def sync_profile():
|
||||||
@@ -1792,7 +1792,7 @@ def set_logfile(filename):
|
|||||||
def do_logprof_pass(logmark='', passno=0, log_pid=log_pid):
|
def do_logprof_pass(logmark='', passno=0, log_pid=log_pid):
|
||||||
# set up variables for this pass
|
# set up variables for this pass
|
||||||
# transitions = hasher()
|
# transitions = hasher()
|
||||||
global existing_profiles
|
global active_profiles
|
||||||
global sev_db
|
global sev_db
|
||||||
# aa = hasher()
|
# aa = hasher()
|
||||||
# profile_changes = hasher()
|
# profile_changes = hasher()
|
||||||
@@ -1809,13 +1809,13 @@ def do_logprof_pass(logmark='', passno=0, log_pid=log_pid):
|
|||||||
if not sev_db:
|
if not sev_db:
|
||||||
sev_db = apparmor.severity.Severity(CONFDIR + '/severity.db', _('unknown'))
|
sev_db = apparmor.severity.Severity(CONFDIR + '/severity.db', _('unknown'))
|
||||||
#print(pid)
|
#print(pid)
|
||||||
#print(existing_profiles)
|
#print(active_profiles)
|
||||||
##if not repo_cf and cfg['repostory']['url']:
|
##if not repo_cf and cfg['repostory']['url']:
|
||||||
## repo_cfg = read_config('repository.conf')
|
## repo_cfg = read_config('repository.conf')
|
||||||
## if not repo_cfg['repository'].get('enabled', False) or repo_cfg['repository]['enabled'] not in ['yes', 'no']:
|
## if not repo_cfg['repository'].get('enabled', False) or repo_cfg['repository]['enabled'] not in ['yes', 'no']:
|
||||||
## UI_ask_to_enable_repo()
|
## UI_ask_to_enable_repo()
|
||||||
|
|
||||||
log_reader = apparmor.logparser.ReadLog(log_pid, logfile, existing_profiles, profile_dir)
|
log_reader = apparmor.logparser.ReadLog(log_pid, logfile, active_profiles, profile_dir)
|
||||||
log = log_reader.read_log(logmark)
|
log = log_reader.read_log(logmark)
|
||||||
#read_log(logmark)
|
#read_log(logmark)
|
||||||
|
|
||||||
@@ -2109,18 +2109,26 @@ def read_profile(file, active_profile):
|
|||||||
|
|
||||||
for profile in profile_data: # TODO: also honor hats
|
for profile in profile_data: # TODO: also honor hats
|
||||||
name = profile_data[profile][profile]['name']
|
name = profile_data[profile][profile]['name']
|
||||||
|
attachment = profile_data[profile][profile]['attachment']
|
||||||
filename = profile_data[profile][profile]['filename']
|
filename = profile_data[profile][profile]['filename']
|
||||||
|
|
||||||
existing_profiles[name] = filename
|
if not attachment and name.startswith('/'):
|
||||||
|
active_profiles.add(filename, name, name) # use name as name and attachment
|
||||||
|
else:
|
||||||
|
active_profiles.add(filename, name, attachment)
|
||||||
|
|
||||||
elif profile_data:
|
elif profile_data:
|
||||||
attach_profile_data(extras, profile_data)
|
attach_profile_data(extras, profile_data)
|
||||||
|
|
||||||
for profile in profile_data: # TODO: also honor hats
|
for profile in profile_data: # TODO: also honor hats
|
||||||
name = profile_data[profile][profile]['name']
|
name = profile_data[profile][profile]['name']
|
||||||
|
attachment = profile_data[profile][profile]['attachment']
|
||||||
filename = profile_data[profile][profile]['filename']
|
filename = profile_data[profile][profile]['filename']
|
||||||
|
|
||||||
existing_profiles[name] = filename
|
if not attachment and name.startswith('/'):
|
||||||
|
extra_profiles.add(filename, name, name) # use name as name and attachment
|
||||||
|
else:
|
||||||
|
extra_profiles.add(filename, name, attachment)
|
||||||
|
|
||||||
def attach_profile_data(profiles, profile_data):
|
def attach_profile_data(profiles, profile_data):
|
||||||
# Make deep copy of data to avoid changes to
|
# Make deep copy of data to avoid changes to
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
|
||||||
# Copyright (C) 2015-2016 Christian Boltz <apparmor@cboltz.de>
|
# Copyright (C) 2015-2018 Christian Boltz <apparmor@cboltz.de>
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of version 2 of the GNU General Public
|
# modify it under the terms of version 2 of the GNU General Public
|
||||||
@@ -43,11 +43,11 @@ class ReadLog:
|
|||||||
# used to pre-filter log lines so that we hand over only relevant lines to LibAppArmor parsing
|
# used to pre-filter log lines so that we hand over only relevant lines to LibAppArmor parsing
|
||||||
RE_LOG_ALL = re.compile('(' + '|'.join(RE_log_parts) + ')')
|
RE_LOG_ALL = re.compile('(' + '|'.join(RE_log_parts) + ')')
|
||||||
|
|
||||||
def __init__(self, pid, filename, existing_profiles, profile_dir):
|
def __init__(self, pid, filename, active_profiles, profile_dir):
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
self.profile_dir = profile_dir
|
self.profile_dir = profile_dir
|
||||||
self.pid = pid
|
self.pid = pid
|
||||||
self.existing_profiles = existing_profiles
|
self.active_profiles = active_profiles
|
||||||
self.log = []
|
self.log = []
|
||||||
self.debug_logger = DebugLogger('ReadLog')
|
self.debug_logger = DebugLogger('ReadLog')
|
||||||
self.LOG = None
|
self.LOG = None
|
||||||
@@ -446,15 +446,16 @@ class ReadLog:
|
|||||||
def profile_exists(self, program):
|
def profile_exists(self, program):
|
||||||
"""Returns True if profile exists, False otherwise"""
|
"""Returns True if profile exists, False otherwise"""
|
||||||
# Check cache of profiles
|
# Check cache of profiles
|
||||||
if self.existing_profiles.get(program, False):
|
if self.active_profiles.filename_from_profile_name(program):
|
||||||
return True
|
return True
|
||||||
# Check the disk for profile
|
# Check the disk for profile
|
||||||
prof_path = self.get_profile_filename(program)
|
prof_path = self.get_profile_filename(program)
|
||||||
#print(prof_path)
|
#print(prof_path)
|
||||||
if os.path.isfile(prof_path):
|
if os.path.isfile(prof_path):
|
||||||
# Add to cache of profile
|
# Add to cache of profile
|
||||||
self.existing_profiles[program] = prof_path
|
raise AppArmorBug('This should never happen, please open a bugreport!')
|
||||||
return True
|
# self.active_profiles[program] = prof_path
|
||||||
|
# return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_profile_filename(self, profile):
|
def get_profile_filename(self, profile):
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#! /usr/bin/python3
|
#! /usr/bin/python3
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# Copyright (C) 2015 Christian Boltz <apparmor@cboltz.de>
|
# Copyright (C) 2015-2018 Christian Boltz <apparmor@cboltz.de>
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of version 2 of the GNU General Public
|
# modify it under the terms of version 2 of the GNU General Public
|
||||||
@@ -17,6 +17,7 @@ from apparmor.common import open_file_read
|
|||||||
|
|
||||||
import apparmor.aa
|
import apparmor.aa
|
||||||
from apparmor.logparser import ReadLog
|
from apparmor.logparser import ReadLog
|
||||||
|
from apparmor.profile_list import ProfileList
|
||||||
|
|
||||||
class TestLibapparmorTestMulti(AATest):
|
class TestLibapparmorTestMulti(AATest):
|
||||||
'''Parse all libraries/libapparmor/testsuite/test_multi tests and compare the result with the *.out files'''
|
'''Parse all libraries/libapparmor/testsuite/test_multi tests and compare the result with the *.out files'''
|
||||||
@@ -222,9 +223,15 @@ class TestLogToProfile(AATest):
|
|||||||
if '//' in profile:
|
if '//' in profile:
|
||||||
profile, hat = profile.split('//')
|
profile, hat = profile.split('//')
|
||||||
|
|
||||||
apparmor.aa.existing_profiles = {profile: profile_dummy_file}
|
apparmor.aa.active_profiles = ProfileList()
|
||||||
|
|
||||||
log_reader = ReadLog(dict(), logfile, apparmor.aa.existing_profiles, '')
|
# optional for now, might be needed one day
|
||||||
|
# if profile.startswith('/'):
|
||||||
|
# apparmor.aa.active_profiles.add(profile_dummy_file, profile, profile)
|
||||||
|
# else:
|
||||||
|
apparmor.aa.active_profiles.add(profile_dummy_file, profile, '')
|
||||||
|
|
||||||
|
log_reader = ReadLog(dict(), logfile, apparmor.aa.active_profiles, '')
|
||||||
log = log_reader.read_log('')
|
log = log_reader.read_log('')
|
||||||
|
|
||||||
for root in log:
|
for root in log:
|
||||||
|
Reference in New Issue
Block a user