apparmor/upstream-changes-r3616..3628.diff
Christian Boltz 8c83a952f7 Accepting request 453533 from home:cboltz
- add upstream-changes-r3616..3628.diff:
  - update abstractions/base, abstractions/apache2-common and dovecot profiles
  - merge ask_the_questions() of aa-logprof and aa-mergeprof
  - pass LDFLAGS when building parser, libapparmor perl bindings and pam_apparmor
- adjust deleting the cache in profiles %post to the new cache location
- silence errors when deleting the cache (boo#976914)

- split libapparmor into separate spec to get rid of build loop
  involving mariadb, systemd, apparmor, libapr and mariadb again
  (see the discussion in SR 448871 for details)

- libapparmor.spec is based on the AppArmor 2.11 apparmor.spec, but
  with minimum BuildRequires

OBS-URL: https://build.opensuse.org/request/show/453533
OBS-URL: https://build.opensuse.org/package/show/security:apparmor/apparmor?expand=0&rev=166
2017-01-30 22:53:15 +00:00

1102 lines
44 KiB
Diff

------------------------------------------------------------
revno: 3628
committer: Christian Boltz <apparmor@cboltz.de>
branch nick: apparmor
timestamp: Mon 2017-01-30 20:43:47 +0100
message:
Dovecot profile: change Px to mrPx for /usr/lib/dovecot/*
Some of the /usr/lib/dovecot/* rules already have mrPx permissions,
while others don't.
With a more recent kernel, I noticed that at least auth, config, dict,
lmtp, pop3 and ssl-params need mrPx instead of just Px (confirmed by the
audit.log and actual breakage caused by the missing mr permissions).
The mr additions for anvil, log and managesieve are just a wild guess,
but I would be very surprised if they don't need mr.
Acked-by: Seth Arnold <seth.arnold@canonical.com> for trunk, 2.10 and 2.9.
------------------------------------------------------------
revno: 3627
fixes bug: https://launchpad.net/bugs/1512131
committer: Christian Boltz <apparmor@cboltz.de>
branch nick: apparmor
timestamp: Thu 2017-01-26 21:41:38 +0100
message:
Dovecot profile update
Add several permissions to the dovecot profiles that are needed on ubuntu
(surprisingly not on openSUSE, maybe it depends on the dovecot config?)
As discussed some weeks ago, the added permissions use only /run/
instead of /{var/,}run/ (which is hopefully superfluous nowadays).
References: https://bugs.launchpad.net/apparmor/+bug/1512131
Acked-by: Seth Arnold <seth.arnold@canonical.com> for trunk, 2.10 and 2.9.
------------------------------------------------------------
revno: 3626
fixes bug: https://launchpad.net/bugs/1658239
author: Kees Cook
committer: Seth Arnold <seth.arnold@canonical.com>
branch nick: apparmor
timestamp: Fri 2017-01-20 17:01:50 -0800
message:
glibc uses /proc/*/auxv and /proc/*/status files, too
Acked-by: Seth Arnold <seth.arnold@canonical.com>
------------------------------------------------------------
revno: 3625
fixes bug: https://launchpad.net/bugs/1658238
author: Kees Cook
committer: Seth Arnold <seth.arnold@canonical.com>
branch nick: apparmor
timestamp: Fri 2017-01-20 16:58:46 -0800
message:
Apache2 profile updates for proper signal handling, optional saslauth,
and OCSP stapling
Acked-by: Seth Arnold <seth.arnold@canonical.com>
------------------------------------------------------------
revno: 3624
committer: Christian Boltz <apparmor@cboltz.de>
branch nick: apparmor
timestamp: Fri 2017-01-20 01:20:41 +0100
message:
Drop unused global variables in aa.py
Grepping through the code shows that running_under_genprof,
unimplemented_warning, ALL, t, seen and skip are unused, so drop them.
Acked-by: Steve Beattie <steve@nxnw.org>
Also drop a '# t = hasher()" comment, as noticed by Steve.
------------------------------------------------------------
revno: 3623
author: Kees Cook <kees@debian.org>
committer: Tyler Hicks <tyhicks@canonical.com>
branch nick: apparmor
timestamp: Thu 2017-01-19 23:04:34 +0000
message:
pass LDFLAGS fully into build
Acked-by: John Johansen <john.johansen@canonical.com>
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
------------------------------------------------------------
revno: 3622
committer: Christian Boltz <apparmor@cboltz.de>
branch nick: apparmor
timestamp: Thu 2017-01-19 16:54:47 +0100
message:
[7/7] Drop most of aa-mergeprof ask_the_questions()
Replace most of aa-mergeprof ask_merge_questions() with a call to
aa.py ask_the_questions() (which is, besides some small exceptions that
are not relevant for aa-mergeprof, in sync with the dropped code).
The remaining part gets renamed to ask_merge_questions() to avoid
confusion with the function name in aa.py. Also drop the (now
superfluous) parameter.
aa.py ask_the_questions() needs to allow 'merge' as aamode.
While on it, replace the fatal_error() call for unknown aamode with
raising an AppArmorBug.
Acked-by: Seth Arnold <seth.arnold@canonical.com>
------------------------------------------------------------
revno: 3621
committer: Christian Boltz <apparmor@cboltz.de>
branch nick: apparmor
timestamp: Thu 2017-01-19 16:52:38 +0100
message:
[6/7] make log_dict a parameter of ask_the_questions()
This allows to hand over any source instead of using the global variable.
Now that the function expects its input as parameter, get rid of the
global log_dict, which means
- change collapse_log() to initialize log_dict as local variable and
return it
- change do_logprof_pass() to catch collapse_log()'s return value and
hand it over to ask_the_questions()
- drop all references to the global log_dict variable
- update test-libapparmor-test_multi to follow the changes
Also fix an if condition that would fail if aa[profile][hat] does not
exist - get() defaults to None if the requested item doesn't exist, and
None.get('file') will raise an Exception.
Acked-by: Seth Arnold <seth.arnold@canonical.com>
------------------------------------------------------------
revno: 3620
committer: Christian Boltz <apparmor@cboltz.de>
branch nick: apparmor
timestamp: Thu 2017-01-19 16:48:44 +0100
message:
[5/7] move ask_conflict_mode() to aa.py
The function is an exact copy of the code in aa-mergeprof (except
removing the 'self' function parameter and changing the whitespace
level)
Also add a ask_conflict_mode() call to aa.py ask_the_questions().
This is needed for aa-mergeprof, and won't hurt in aa-logprof mode
because handle_children() already handles all exec events.
Acked-by: Seth Arnold <seth.arnold@canonical.com>
------------------------------------------------------------
revno: 3619
committer: Christian Boltz <apparmor@cboltz.de>
branch nick: apparmor
timestamp: Thu 2017-01-19 16:47:35 +0100
message:
[4/7] Copy code to ask for adding hats to aa.py ask_the_questions()
Everything below "if aamode == 'merge':" is an exact copy of the code in
aa-mergeprof (with whitespace changed).
aa-logprof and aa-mergeprof will continue to ignore events from unknown
hats and subprofiles.
Acked-by: Seth Arnold <seth.arnold@canonical.com>
------------------------------------------------------------
revno: 3618
committer: Christian Boltz <apparmor@cboltz.de>
branch nick: apparmor
timestamp: Thu 2017-01-19 16:47:05 +0100
message:
[3/7] Copy code to ask for adding includes to aa.py ask_the_questions()
This is an exact copy of the code in aa-mergeprof (with whitespace changed).
Acked-by: Seth Arnold <seth.arnold@canonical.com>
------------------------------------------------------------
revno: 3617
committer: Christian Boltz <apparmor@cboltz.de>
branch nick: apparmor
timestamp: Thu 2017-01-19 16:46:23 +0100
message:
[2/7] replace other.aa with log_dict['merge']
Set log_dict['merge'] = other.aa and aamode = 'merge', and use
log_dict[aamode] everywhere.
This brings aa-mergeprof ask_the_questions() closer to the code in aa.py.
Acked-by: Seth Arnold <seth.arnold@canonical.com>
------------------------------------------------------------
revno: 3616
committer: Christian Boltz <apparmor@cboltz.de>
branch nick: apparmor
timestamp: Thu 2017-01-19 16:45:29 +0100
message:
[1/7] drop traces of 3-way-merge in aa-mergeprof
3-way-merge was never really implemented.
This patch drops all traces of it to make the code more readable and
easier to maintain.
Acked-by: Seth Arnold <seth.arnold@canonical.com>
=== modified file 'changehat/pam_apparmor/Makefile'
--- changehat/pam_apparmor/Makefile 2016-12-10 18:25:31 +0000
+++ changehat/pam_apparmor/Makefile 2017-01-19 23:04:34 +0000
@@ -55,7 +55,7 @@
AA_LDLIBS = -lapparmor
endif
EXTRA_CFLAGS=$(CFLAGS) $(CPPFLAGS) -fPIC -shared -Wall $(LIBAPPARMOR_INCLUDE)
-LINK_FLAGS=-Xlinker -x $(AA_LINK_FLAGS)
+LINK_FLAGS=-Xlinker -x $(AA_LINK_FLAGS) $(LDFLAGS)
LIBS=-lpam $(AA_LDLIBS)
OBJECTS=${NAME}.o get_options.o
=== modified file 'libraries/libapparmor/swig/perl/Makefile.PL.in'
--- libraries/libapparmor/swig/perl/Makefile.PL.in 2014-01-06 22:08:55 +0000
+++ libraries/libapparmor/swig/perl/Makefile.PL.in 2017-01-19 23:04:34 +0000
@@ -13,5 +13,6 @@
'INC' => q[@CPPFLAGS@ -I@top_srcdir@/include @CFLAGS@],
'LIBS' => q[-L@top_builddir@/src/.libs/ -lapparmor @LIBS@],
'OBJECT' => 'libapparmor_wrap.o', # $(OBJ_EXT)
+ 'dynamic_lib' => { 'OTHERLDFLAGS' => q[@LDFLAGS@], },
) ;
=== modified file 'parser/Makefile'
--- parser/Makefile 2016-12-10 18:25:31 +0000
+++ parser/Makefile 2017-01-19 23:04:34 +0000
@@ -86,7 +86,7 @@
AAREDIR= libapparmor_re
AAREOBJECT = ${AAREDIR}/libapparmor_re.a
AAREOBJECTS = $(AAREOBJECT)
-AARE_LDFLAGS = -static-libgcc -static-libstdc++ -L.
+AARE_LDFLAGS = -static-libgcc -static-libstdc++ -L. $(LDFLAGS)
AALIB = -Wl,-Bstatic -lapparmor -Wl,-Bdynamic -lpthread
ifdef USE_SYSTEM
=== modified file 'profiles/apparmor.d/abstractions/apache2-common'
--- profiles/apparmor.d/abstractions/apache2-common 2014-06-24 18:06:06 +0000
+++ profiles/apparmor.d/abstractions/apache2-common 2017-01-21 00:58:46 +0000
@@ -8,6 +8,8 @@
signal (receive) peer=unconfined,
# Allow apache to send us signals by default
signal (receive) peer=/usr/sbin/apache2,
+ # Allow other hats to signal by default
+ signal peer=/usr/sbin/apache2//*,
# Allow us to signal ourselves
signal peer=@{profile_name},
@@ -25,3 +27,8 @@
/dev/urandom r,
+ # sasl-auth
+ /run/saslauthd/mux rw,
+
+ # OCSP stapling
+ /var/log/apache2/stapling-cache rw,
=== modified file 'profiles/apparmor.d/abstractions/base'
--- profiles/apparmor.d/abstractions/base 2016-12-03 15:52:47 +0000
+++ profiles/apparmor.d/abstractions/base 2017-01-21 01:01:50 +0000
@@ -85,7 +85,7 @@
/sys/devices/system/cpu/online r,
# glibc's *printf protections read the maps file
- @{PROC}/@{pid}/maps r,
+ @{PROC}/@{pid}/{maps,auxv,status} r,
# libgcrypt reads some flags from /proc
@{PROC}/sys/crypto/* r,
=== modified file 'profiles/apparmor.d/usr.lib.dovecot.anvil'
--- profiles/apparmor.d/usr.lib.dovecot.anvil 2014-06-27 19:14:53 +0000
+++ profiles/apparmor.d/usr.lib.dovecot.anvil 2017-01-26 20:41:38 +0000
@@ -18,6 +18,7 @@
capability setuid,
capability sys_chroot,
+ /run/dovecot/anvil rw,
/usr/lib/dovecot/anvil mr,
# Site-specific additions and overrides. See local/README for details.
=== modified file 'profiles/apparmor.d/usr.lib.dovecot.auth'
--- profiles/apparmor.d/usr.lib.dovecot.auth 2016-12-27 16:46:07 +0000
+++ profiles/apparmor.d/usr.lib.dovecot.auth 2017-01-26 20:41:38 +0000
@@ -37,6 +37,9 @@
/var/tmp/sieve_* rw,
/var/tmp/smtp_* rw,
+ /run/dovecot/auth-master rw,
+ /run/dovecot/auth-worker rw,
+ /run/dovecot/login/login rw,
/{var/,}run/dovecot/auth-token-secret.dat{,.tmp} rw,
/{var/,}run/dovecot/stats-user rw,
/{var/,}run/dovecot/anvil-auth-penalty rw,
=== modified file 'profiles/apparmor.d/usr.lib.dovecot.imap'
--- profiles/apparmor.d/usr.lib.dovecot.imap 2016-10-05 18:46:03 +0000
+++ profiles/apparmor.d/usr.lib.dovecot.imap 2017-01-26 20:41:38 +0000
@@ -21,6 +21,8 @@
capability setuid,
deny capability block_suspend,
+ network unix stream,
+
@{DOVECOT_MAILSTORE}/ rw,
@{DOVECOT_MAILSTORE}/** rwkl,
@@ -33,6 +35,7 @@
/usr/bin/doveconf rix,
/usr/lib/dovecot/imap mrix,
/usr/share/dovecot/** r,
+ /run/dovecot/login/imap rw,
/{,var/}run/dovecot/auth-master rw,
/{,var/}run/dovecot/mounts r,
=== modified file 'profiles/apparmor.d/usr.lib.dovecot.imap-login'
--- profiles/apparmor.d/usr.lib.dovecot.imap-login 2014-12-22 16:41:59 +0000
+++ profiles/apparmor.d/usr.lib.dovecot.imap-login 2017-01-26 20:41:38 +0000
@@ -22,6 +22,7 @@
network inet stream,
network inet6 stream,
+ network unix stream,
/usr/lib/dovecot/imap-login mr,
/{,var/}run/dovecot/anvil rw,
=== modified file 'profiles/apparmor.d/usr.lib.dovecot.ssl-params'
--- profiles/apparmor.d/usr.lib.dovecot.ssl-params 2014-06-27 19:14:53 +0000
+++ profiles/apparmor.d/usr.lib.dovecot.ssl-params 2017-01-26 20:41:38 +0000
@@ -15,6 +15,7 @@
#include <abstractions/base>
#include <abstractions/dovecot-common>
+ /run/dovecot/login/ssl-params rw,
/usr/lib/dovecot/ssl-params mr,
/var/lib/dovecot/ssl-parameters.dat rw,
/var/lib/dovecot/ssl-parameters.dat.tmp rwk,
=== modified file 'profiles/apparmor.d/usr.sbin.dovecot'
--- profiles/apparmor.d/usr.sbin.dovecot 2016-11-29 20:35:14 +0000
+++ profiles/apparmor.d/usr.sbin.dovecot 2017-01-30 19:43:47 +0000
@@ -36,21 +36,21 @@
/etc/SuSE-release r,
@{PROC}/@{pid}/mounts r,
/usr/bin/doveconf rix,
- /usr/lib/dovecot/anvil Px,
- /usr/lib/dovecot/auth Px,
- /usr/lib/dovecot/config Px,
- /usr/lib/dovecot/dict Px,
+ /usr/lib/dovecot/anvil mrPx,
+ /usr/lib/dovecot/auth mrPx,
+ /usr/lib/dovecot/config mrPx,
+ /usr/lib/dovecot/dict mrPx,
/usr/lib/dovecot/dovecot-auth Pxmr,
/usr/lib/dovecot/imap Pxmr,
/usr/lib/dovecot/imap-login Pxmr,
- /usr/lib/dovecot/lmtp Px,
- /usr/lib/dovecot/log Px,
- /usr/lib/dovecot/managesieve Px,
+ /usr/lib/dovecot/lmtp mrPx,
+ /usr/lib/dovecot/log mrPx,
+ /usr/lib/dovecot/managesieve mrPx,
/usr/lib/dovecot/managesieve-login Pxmr,
- /usr/lib/dovecot/pop3 Px,
+ /usr/lib/dovecot/pop3 mrPx,
/usr/lib/dovecot/pop3-login Pxmr,
/usr/lib/dovecot/ssl-build-param rix,
- /usr/lib/dovecot/ssl-params Px,
+ /usr/lib/dovecot/ssl-params mrPx,
/usr/sbin/dovecot mrix,
/usr/share/dovecot/protocols.d/ r,
/usr/share/dovecot/protocols.d/** r,
=== modified file 'utils/aa-mergeprof'
--- utils/aa-mergeprof 2016-10-01 18:57:09 +0000
+++ utils/aa-mergeprof 2017-01-19 15:54:47 +0000
@@ -1,7 +1,7 @@
#! /usr/bin/python3
# ----------------------------------------------------------------------
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
-# Copyright (C) 2014-2016 Christian Boltz <apparmor@cboltz.de>
+# Copyright (C) 2014-2017 Christian Boltz <apparmor@cboltz.de>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
@@ -23,10 +23,6 @@
import apparmor.cleanprofile as cleanprofile
import apparmor.ui as aaui
-from apparmor.aa import (add_to_options, available_buttons, combine_name, delete_duplicates,
- get_profile_filename, is_known_rule, match_includes, profile_storage,
- set_options_audit_mode, propose_file_rules, selection_to_rule_obj)
-from apparmor.aare import AARE
from apparmor.common import AppArmorException
from apparmor.regex import re_match_include
@@ -41,16 +37,13 @@
parser = argparse.ArgumentParser(description=_('Merge the given profiles into /etc/apparmor.d/ (or the directory specified with -d)'))
parser.add_argument('files', nargs='+', type=str, help=_('Profile(s) to merge'))
-#parser.add_argument('other', nargs='?', type=str, help=_('other profile'))
parser.add_argument('-d', '--dir', type=str, help=_('path to profiles'))
#parser.add_argument('-a', '--auto', action='store_true', help=_('Automatically merge profiles, exits incase of *x conflicts'))
args = parser.parse_args()
args.other = None
-# 2-way merge or 3-way merge based on number of params
-merge_mode = 2 #if args.other == None else 3
-profiles = [args.files, [args.other]]
+profiles = args.files
profiledir = args.dir
if profiledir:
@@ -87,61 +80,29 @@
return profile_to_filename
def main():
- profiles_to_merge = set()
-
- base_files, other_files = profiles
-
- base_profile_to_file = find_profiles_from_files(base_files)
-
- profiles_to_merge = profiles_to_merge.union(set(base_profile_to_file.keys()))
-
- other_profile_to_file = dict()
-
- if merge_mode == 3:
- other_profile_to_file = find_profiles_from_files(other_files)
- profiles_to_merge.add(other_profile_to_file.keys())
+ base_profile_to_file = find_profiles_from_files(profiles)
+
+ profiles_to_merge = set(base_profile_to_file.keys())
user_profile_to_file = find_files_from_profiles(profiles_to_merge)
-# print(base_files,"\n",other_files)
-# print(base_profile_to_file,"\n",other_profile_to_file,"\n",user_profile_to_file)
-# print(profiles_to_merge)
-
for profile_name in profiles_to_merge:
aaui.UI_Info("\n\n" + _("Merging profile for %s" % profile_name))
user_file = user_profile_to_file[profile_name]
base_file = base_profile_to_file.get(profile_name, None)
- other_file = None
-
- if merge_mode == 3:
- other_file = other_profile_to_file.get(profile_name, None)
-
- if base_file == None:
- if other_file == None:
- continue
-
- act([user_file, other_file, None], 2, profile_name)
- else:
- if other_file == None:
- act([user_file, base_file, None], 2, profile_name)
- else:
- act([user_file, base_file, other_file], 3, profile_name)
+
+ act([user_file, base_file], profile_name)
reset_aa()
-def act(files, merge_mode, merging_profile):
+def act(files, merging_profile):
mergeprofiles = Merge(files)
#Get rid of common/superfluous stuff
mergeprofiles.clear_common()
# if not args.auto:
if 1 == 1: # workaround to avoid lots of whitespace changes
- if merge_mode == 3:
- mergeprofiles.ask_the_questions('other', merging_profile)
-
- mergeprofiles.clear_common()
-
- mergeprofiles.ask_the_questions('base', merging_profile)
+ mergeprofiles.ask_merge_questions()
q = aaui.PromptQuestion()
q.title = _('Changed Local Profiles')
@@ -172,7 +133,7 @@
class Merge(object):
def __init__(self, profiles):
- user, base, other = profiles
+ user, base = profiles
#Read and parse base profile and save profile data, include data from it and reset them
apparmor.aa.read_profile(base, True)
@@ -180,12 +141,6 @@
reset_aa()
- #Read and parse other profile and save profile data, include data from it and reset them
- if merge_mode == 3:
- apparmor.aa.read_profile(other, True)
- self.other = cleanprofile.Prof(other)
- reset_aa()
-
#Read and parse user profile
apparmor.aa.read_profile(user, True)
self.user = cleanprofile.Prof(user)
@@ -193,67 +148,18 @@
def clear_common(self):
deleted = 0
- if merge_mode == 3:
- #Remove off the parts in other profile which are common/superfluous from user profile
- user_other = cleanprofile.CleanProf(False, self.user, self.other)
- deleted += user_other.compare_profiles()
-
#Remove off the parts in base profile which are common/superfluous from user profile
user_base = cleanprofile.CleanProf(False, self.user, self.base)
deleted += user_base.compare_profiles()
- if merge_mode == 3:
- #Remove off the parts in other profile which are common/superfluous from base profile
- base_other = cleanprofile.CleanProf(False, self.base, self.other)
- deleted += base_other.compare_profiles()
-
- def ask_conflict_mode(self, profile, hat, old_profile, merge_profile):
- '''ask user about conflicting exec rules'''
- for oldrule in old_profile['file'].rules:
- conflictingrules = merge_profile['file'].get_exec_conflict_rules(oldrule)
-
- if conflictingrules.rules:
- q = aaui.PromptQuestion()
- q.headers = [_('Path'), oldrule.path.regex]
- q.headers += [_('Select the appropriate mode'), '']
- options = []
- options.append(oldrule.get_clean())
- for rule in conflictingrules.rules:
- options.append(rule.get_clean())
- q.options = options
- q.functions = ['CMD_ALLOW', 'CMD_ABORT']
- done = False
- while not done:
- ans, selected = q.promptUser()
- if ans == 'CMD_ALLOW':
- if selected == 0:
- pass # just keep the existing rule
- elif selected > 0:
- # replace existing rule with merged one
- old_profile['file'].delete(oldrule)
- old_profile['file'].add(conflictingrules.rules[selected - 1])
- else:
- raise AppArmorException(_('Unknown selection'))
-
- for rule in conflictingrules.rules:
- merge_profile['file'].delete(rule) # make sure aa-mergeprof doesn't ask to add conflicting rules later
-
- done = True
-
- def ask_the_questions(self, other, profile):
- aa = self.user.aa # keep references so that the code in this function can use the short name
- changed = apparmor.aa.changed # (and be more in sync with aa.py ask_the_questions())
-
- if other == 'other':
- other = self.other
- else:
- other = self.base
- #print(other.aa)
-
- #Add the file-wide includes from the other profile to the user profile
+ def ask_merge_questions(self):
+ other = self.base
+ log_dict = {'merge': other.aa}
+
apparmor.aa.loadincludes()
done = False
+ #Add the file-wide includes from the other profile to the user profile
options = []
for inc in other.filelist[other.filename]['include'].keys():
if not inc in self.user.filelist[self.user.filename]['include'].keys():
@@ -281,211 +187,10 @@
elif ans == 'CMD_FINISHED':
return
- sev_db = apparmor.aa.sev_db
- if not sev_db:
- sev_db = apparmor.severity.Severity(apparmor.aa.CONFDIR + '/severity.db', _('unknown'))
-
- sev_db.unload_variables()
- sev_db.load_variables(get_profile_filename(profile))
-
- for hat in sorted(other.aa[profile].keys()):
-
- if not aa[profile].get(hat):
- ans = ''
- while ans not in ['CMD_ADDHAT', 'CMD_ADDSUBPROFILE', 'CMD_DENY']:
- q = aaui.PromptQuestion()
- q.headers += [_('Profile'), profile]
-
- if other.aa[profile][hat]['profile']:
- q.headers += [_('Requested Subprofile'), hat]
- q.functions.append('CMD_ADDSUBPROFILE')
- else:
- q.headers += [_('Requested Hat'), hat]
- q.functions.append('CMD_ADDHAT')
-
- q.functions += ['CMD_DENY', 'CMD_ABORT', 'CMD_FINISHED']
-
- q.default = 'CMD_DENY'
-
- ans = q.promptUser()[0]
-
- if ans == 'CMD_FINISHED':
- return
-
- if ans == 'CMD_DENY':
- continue # don't ask about individual rules if the user doesn't want the additional subprofile/hat
-
- if other.aa[profile][hat]['profile']:
- aa[profile][hat] = profile_storage(profile, hat, 'mergeprof ask_the_questions() - missing subprofile')
- aa[profile][hat]['profile'] = True
- else:
- aa[profile][hat] = profile_storage(profile, hat, 'mergeprof ask_the_questions() - missing hat')
- aa[profile][hat]['profile'] = False
-
- #Add the includes from the other profile to the user profile
- done = False
-
- options = []
- for inc in other.aa[profile][hat]['include'].keys():
- if not inc in aa[profile][hat]['include'].keys():
- options.append('#include <%s>' %inc)
-
- default_option = 1
-
- q = aaui.PromptQuestion()
- q.options = options
- q.selected = default_option - 1
- q.headers = [_('File includes'), _('Select the ones you wish to add')]
- q.functions = ['CMD_ALLOW', 'CMD_IGNORE_ENTRY', 'CMD_ABORT', 'CMD_FINISHED']
- q.default = 'CMD_ALLOW'
-
- while not done and options:
- ans, selected = q.promptUser()
- if ans == 'CMD_IGNORE_ENTRY':
- done = True
- elif ans == 'CMD_ALLOW':
- selection = options[selected]
- inc = re_match_include(selection)
- deleted = apparmor.aa.delete_duplicates(aa[profile][hat], inc)
- aa[profile][hat]['include'][inc] = True
- options.pop(selected)
- aaui.UI_Info(_('Adding %s to the file.') % selection)
- if deleted:
- aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
- elif ans == 'CMD_FINISHED':
- return
-
- # check for and ask about conflicting exec modes
- self.ask_conflict_mode(profile, hat, aa[profile][hat], other.aa[profile][hat])
-
- for ruletype in apparmor.aa.ruletypes:
- if other.aa[profile][hat].get(ruletype, False): # needed until we have proper profile initialization
- for rule_obj in other.aa[profile][hat][ruletype].rules:
-
- if is_known_rule(aa[profile][hat], ruletype, rule_obj):
- continue
-
- default_option = 1
- options = []
- newincludes = match_includes(aa[profile][hat], ruletype, rule_obj)
- q = aaui.PromptQuestion()
- if newincludes:
- options += list(map(lambda inc: '#include <%s>' % inc, sorted(set(newincludes))))
-
- if ruletype == 'file' and rule_obj.path:
- options += propose_file_rules(aa[profile][hat], rule_obj)
- else:
- options.append(rule_obj.get_clean())
-
- done = False
- while not done:
- q.options = options
- q.selected = default_option - 1
- q.headers = [_('Profile'), combine_name(profile, hat)]
- q.headers += rule_obj.logprof_header()
-
- # Load variables into sev_db? Not needed/used for capabilities and network rules.
- severity = rule_obj.severity(sev_db)
- if severity != sev_db.NOT_IMPLEMENTED:
- q.headers += [_('Severity'), severity]
-
- q.functions = available_buttons(rule_obj)
- q.default = q.functions[0]
-
- ans, selected = q.promptUser()
- selection = options[selected]
- if ans == 'CMD_IGNORE_ENTRY':
- done = True
- break
-
- elif ans == 'CMD_FINISHED':
- return
-
- elif ans.startswith('CMD_AUDIT'):
- if ans == 'CMD_AUDIT_NEW':
- rule_obj.audit = True
- rule_obj.raw_rule = None
- else:
- rule_obj.audit = False
- rule_obj.raw_rule = None
-
- options = set_options_audit_mode(rule_obj, options)
-
- elif ans == 'CMD_ALLOW':
- done = True
- changed[profile] = True
-
- inc = re_match_include(selection)
- if inc:
- deleted = delete_duplicates(aa[profile][hat], inc)
-
- aa[profile][hat]['include'][inc] = True
-
- aaui.UI_Info(_('Adding %s to profile.') % selection)
- if deleted:
- aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
-
- else:
- rule_obj = selection_to_rule_obj(rule_obj, selection)
- deleted = aa[profile][hat][ruletype].add(rule_obj, cleanup=True)
-
- aaui.UI_Info(_('Adding %s to profile.') % rule_obj.get_clean())
- if deleted:
- aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
-
- elif ans == 'CMD_DENY':
- if re_match_include(selection):
- aaui.UI_Important("Denying via an include file isn't supported by the AppArmor tools")
-
- else:
- done = True
- changed[profile] = True
-
- rule_obj = selection_to_rule_obj(rule_obj, selection)
- rule_obj.deny = True
- rule_obj.raw_rule = None # reset raw rule after manually modifying rule_obj
- deleted = aa[profile][hat][ruletype].add(rule_obj, cleanup=True)
- aaui.UI_Info(_('Adding %s to profile.') % rule_obj.get_clean())
- if deleted:
- aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
-
- elif ans == 'CMD_GLOB':
- if not re_match_include(selection):
- globbed_rule_obj = selection_to_rule_obj(rule_obj, selection)
- globbed_rule_obj.glob()
- options, default_option = add_to_options(options, globbed_rule_obj.get_raw())
-
- elif ans == 'CMD_GLOBEXT':
- if not re_match_include(selection):
- globbed_rule_obj = selection_to_rule_obj(rule_obj, selection)
- globbed_rule_obj.glob_ext()
- options, default_option = add_to_options(options, globbed_rule_obj.get_raw())
-
- elif ans == 'CMD_NEW':
- if not re_match_include(selection):
- edit_rule_obj = selection_to_rule_obj(rule_obj, selection)
- prompt, oldpath = edit_rule_obj.edit_header()
-
- newpath = aaui.UI_GetString(prompt, oldpath)
- if newpath:
- try:
- input_matches_path = rule_obj.validate_edit(newpath) # note that we check against the original rule_obj here, not edit_rule_obj (which might be based on a globbed path)
- except AppArmorException:
- aaui.UI_Important(_('The path you entered is invalid (not starting with / or a variable)!'))
- continue
-
- if not input_matches_path:
- ynprompt = _('The specified path does not match this log entry:\n\n Log Entry: %(path)s\n Entered Path: %(ans)s\nDo you really want to use this path?') % { 'path': oldpath, 'ans': newpath }
- key = aaui.UI_YesNo(ynprompt, 'n')
- if key == 'n':
- continue
-
- edit_rule_obj.store_edit(newpath)
- options, default_option = add_to_options(options, edit_rule_obj.get_raw())
- apparmor.aa.user_globs[newpath] = AARE(newpath, True)
-
- else:
- done = False
+ if not apparmor.aa.sev_db:
+ apparmor.aa.sev_db = apparmor.severity.Severity(apparmor.aa.CONFDIR + '/severity.db', _('unknown'))
+
+ apparmor.aa.ask_the_questions(log_dict)
if __name__ == '__main__':
main()
=== modified file 'utils/apparmor/aa.py'
--- utils/apparmor/aa.py 2016-12-30 23:48:41 +0000
+++ utils/apparmor/aa.py 2017-01-20 00:20:41 +0000
@@ -1,6 +1,6 @@
# ----------------------------------------------------------------------
# Copyright (C) 2013 Kshitij Gupta <kgupta8592@gmail.com>
-# Copyright (C) 2014-2016 Christian Boltz <apparmor@cboltz.de>
+# Copyright (C) 2014-2017 Christian Boltz <apparmor@cboltz.de>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public
@@ -74,8 +74,6 @@
debug_logger = DebugLogger('aa')
CONFDIR = '/etc/apparmor'
-running_under_genprof = False
-unimplemented_warning = False
# The database for severity
sev_db = None
@@ -99,12 +97,7 @@
# format: user_globs['/foo*'] = AARE('/foo*')
user_globs = {}
-# The key for representing bare "file," rules
-ALL = '\0ALL'
-
## Variables used under logprof
-### Were our
-t = hasher() # dict()
transitions = hasher()
aa = hasher() # Profiles originally in sd, replace by aa
@@ -114,13 +107,10 @@
log = []
pid = dict()
-seen = hasher() # dir()
profile_changes = hasher()
prelog = hasher()
-log_dict = hasher() # dict()
changed = dict()
created = []
-skip = hasher()
helpers = dict() # Preserve this between passes # was our
### logprof ends
@@ -1486,16 +1476,17 @@
return globs
-def ask_the_questions():
+def ask_the_questions(log_dict):
for aamode in sorted(log_dict.keys()):
# Describe the type of changes
if aamode == 'PERMITTING':
aaui.UI_Info(_('Complain-mode changes:'))
elif aamode == 'REJECTING':
aaui.UI_Info(_('Enforce-mode changes:'))
+ elif aamode == 'merge':
+ pass # aa-mergeprof
else:
- # This is so wrong!
- fatal_error(_('Invalid mode found: %s') % aamode)
+ raise AppArmorBug(_('Invalid mode found: %s') % aamode)
for profile in sorted(log_dict[aamode].keys()):
# Update the repo profiles
@@ -1513,16 +1504,83 @@
for hat in hats:
- if not aa[profile].get(hat).get('file'):
- # Ignore log events for a non-existing profile or child profile. Such events can occour
- # after deleting a profile or hat manually, or when processing a foreign log.
- # (Checking for 'file' is a simplified way to check if it's a profile_storage() struct.)
- debug_logger.debug("Ignoring events for non-existing profile %s" % combine_name(profile, hat))
- continue
+ if not aa[profile].get(hat, {}).get('file'):
+ if aamode != 'merge':
+ # Ignore log events for a non-existing profile or child profile. Such events can occour
+ # after deleting a profile or hat manually, or when processing a foreign log.
+ # (Checking for 'file' is a simplified way to check if it's a profile_storage() struct.)
+ debug_logger.debug("Ignoring events for non-existing profile %s" % combine_name(profile, hat))
+ continue
+
+ ans = ''
+ while ans not in ['CMD_ADDHAT', 'CMD_ADDSUBPROFILE', 'CMD_DENY']:
+ q = aaui.PromptQuestion()
+ q.headers += [_('Profile'), profile]
+
+ if log_dict[aamode][profile][hat]['profile']:
+ q.headers += [_('Requested Subprofile'), hat]
+ q.functions.append('CMD_ADDSUBPROFILE')
+ else:
+ q.headers += [_('Requested Hat'), hat]
+ q.functions.append('CMD_ADDHAT')
+
+ q.functions += ['CMD_DENY', 'CMD_ABORT', 'CMD_FINISHED']
+
+ q.default = 'CMD_DENY'
+
+ ans = q.promptUser()[0]
+
+ if ans == 'CMD_FINISHED':
+ return
+
+ if ans == 'CMD_DENY':
+ continue # don't ask about individual rules if the user doesn't want the additional subprofile/hat
+
+ if log_dict[aamode][profile][hat]['profile']:
+ aa[profile][hat] = profile_storage(profile, hat, 'mergeprof ask_the_questions() - missing subprofile')
+ aa[profile][hat]['profile'] = True
+ else:
+ aa[profile][hat] = profile_storage(profile, hat, 'mergeprof ask_the_questions() - missing hat')
+ aa[profile][hat]['profile'] = False
+
+ #Add the includes from the other profile to the user profile
+ done = False
+
+ options = []
+ for inc in log_dict[aamode][profile][hat]['include'].keys():
+ if not inc in aa[profile][hat]['include'].keys():
+ options.append('#include <%s>' %inc)
+
+ default_option = 1
+
+ q = aaui.PromptQuestion()
+ q.options = options
+ q.selected = default_option - 1
+ q.headers = [_('File includes'), _('Select the ones you wish to add')]
+ q.functions = ['CMD_ALLOW', 'CMD_IGNORE_ENTRY', 'CMD_ABORT', 'CMD_FINISHED']
+ q.default = 'CMD_ALLOW'
+
+ while not done and options:
+ ans, selected = q.promptUser()
+ if ans == 'CMD_IGNORE_ENTRY':
+ done = True
+ elif ans == 'CMD_ALLOW':
+ selection = options[selected]
+ inc = re_match_include(selection)
+ deleted = apparmor.aa.delete_duplicates(aa[profile][hat], inc)
+ aa[profile][hat]['include'][inc] = True
+ options.pop(selected)
+ aaui.UI_Info(_('Adding %s to the file.') % selection)
+ if deleted:
+ aaui.UI_Info(_('Deleted %s previous matching profile entries.') % deleted)
+ elif ans == 'CMD_FINISHED':
+ return
+
+ # check for and ask about conflicting exec modes
+ ask_conflict_mode(profile, hat, aa[profile][hat], log_dict[aamode][profile][hat])
for ruletype in ruletypes:
for rule_obj in log_dict[aamode][profile][hat][ruletype].rules:
- # XXX aa-mergeprof also has this code - if you change it, keep aa-mergeprof in sync!
if is_known_rule(aa[profile][hat], ruletype, rule_obj):
continue
@@ -1655,7 +1713,6 @@
else:
done = False
- # END of code (mostly) shared with aa-mergeprof
def selection_to_rule_obj(rule_obj, selection):
rule_type = type(rule_obj)
@@ -1726,6 +1783,39 @@
return deleted
+def ask_conflict_mode(profile, hat, old_profile, merge_profile):
+ '''ask user about conflicting exec rules'''
+ for oldrule in old_profile['file'].rules:
+ conflictingrules = merge_profile['file'].get_exec_conflict_rules(oldrule)
+
+ if conflictingrules.rules:
+ q = aaui.PromptQuestion()
+ q.headers = [_('Path'), oldrule.path.regex]
+ q.headers += [_('Select the appropriate mode'), '']
+ options = []
+ options.append(oldrule.get_clean())
+ for rule in conflictingrules.rules:
+ options.append(rule.get_clean())
+ q.options = options
+ q.functions = ['CMD_ALLOW', 'CMD_ABORT']
+ done = False
+ while not done:
+ ans, selected = q.promptUser()
+ if ans == 'CMD_ALLOW':
+ if selected == 0:
+ pass # just keep the existing rule
+ elif selected > 0:
+ # replace existing rule with merged one
+ old_profile['file'].delete(oldrule)
+ old_profile['file'].add(conflictingrules.rules[selected - 1])
+ else:
+ raise AppArmorException(_('Unknown selection'))
+
+ for rule in conflictingrules.rules:
+ merge_profile['file'].delete(rule) # make sure aa-mergeprof doesn't ask to add conflicting rules later
+
+ done = True
+
def match_includes(profile, rule_type, rule_obj):
newincludes = []
for incname in include.keys():
@@ -1769,9 +1859,7 @@
def do_logprof_pass(logmark='', passno=0, pid=pid):
# set up variables for this pass
-# t = hasher()
# transitions = hasher()
-# seen = hasher() # XXX global?
global log
log = []
global existing_profiles
@@ -1779,9 +1867,7 @@
# aa = hasher()
# profile_changes = hasher()
# prelog = hasher()
-# log_dict = hasher()
# changed = dict()
-# skip = hasher() # XXX global?
# filelist = hasher()
aaui.UI_Info(_('Reading log entries from %s.') % logfile)
@@ -1811,9 +1897,9 @@
for pid in sorted(profile_changes.keys()):
set_process(pid, profile_changes[pid])
- collapse_log()
+ log_dict = collapse_log()
- ask_the_questions()
+ ask_the_questions(log_dict)
if aaui.UI_mode == 'yast':
# To-Do
@@ -2019,6 +2105,7 @@
process.close()
def collapse_log():
+ log_dict = hasher()
for aamode in prelog.keys():
for profile in prelog[aamode].keys():
for hat in prelog[aamode][profile].keys():
@@ -2099,6 +2186,8 @@
if not is_known_rule(aa[profile][hat], 'signal', signal_event):
log_dict[aamode][profile][hat]['signal'].add(signal_event)
+ return log_dict
+
def is_skippable_file(path):
"""Returns True if filename matches something to be skipped (rpm or dpkg backup files, hidden files etc.)
The list of skippable files needs to be synced with apparmor initscript and libapparmor _aa_is_blacklisted()
=== modified file 'utils/test/test-libapparmor-test_multi.py'
--- utils/test/test-libapparmor-test_multi.py 2016-11-01 20:40:29 +0000
+++ utils/test/test-libapparmor-test_multi.py 2017-01-19 15:52:38 +0000
@@ -214,7 +214,6 @@
apparmor.aa.log = dict()
apparmor.aa.aa = apparmor.aa.hasher()
apparmor.aa.prelog = apparmor.aa.hasher()
- apparmor.aa.log_dict = apparmor.aa.hasher()
profile = parsed_event['profile']
hat = profile
@@ -229,12 +228,12 @@
for root in log:
apparmor.aa.handle_children('', '', root) # interactive for exec events!
- apparmor.aa.collapse_log()
+ log_dict = apparmor.aa.collapse_log()
apparmor.aa.filelist = apparmor.aa.hasher()
apparmor.aa.filelist[profile_dummy_file]['profiles'][profile] = True
- new_profile = apparmor.aa.serialize_profile(apparmor.aa.log_dict[aamode][profile], profile, None)
+ new_profile = apparmor.aa.serialize_profile(log_dict[aamode][profile], profile, None)
expected_profile = read_file('%s.profile' % params)
vim:ft=diff