apparmor/upstream-changes-r3629..3648.diff
Christian Boltz 454b681e13 Accepting request 482764 from home:cboltz
- add upstream-changes-r-3629..3648.diff:
  - preserve unknown profiles when reloading apparmor.service
    (CVE-2017-6507, lp#1668892, boo#1029696)
  - add aa-remove-unknown utility to unload unknown profiles (lp#1668892)
  - update nvidia abstraction for newer nvidia drivers
  - don't enforce ordering of dbus rule attributes in utils (lp#1628286)
  - add --parser, --base and --Include option to aa-easyprof to allow
    non-standard paths (useful for tests) (lp#1521031)
  - move initialization code in apparmor.aa to init_aa(). This allows to
    run all utils tests even if /etc/apparmor.d/ or /sbin/apparmor_parser
    don't exist.
  - several improvements in the utils tests
- drop upstreamed python3-drop-re-locale.patch
- no longer delete/skip some of the utils tests (to allow this, add
  parser-tests-dbus-duplicated-conditionals.diff)
- add var.mount dependeny to apparmor.service (boo#1016259#c34)

OBS-URL: https://build.opensuse.org/request/show/482764
OBS-URL: https://build.opensuse.org/package/show/security:apparmor/apparmor?expand=0&rev=174
2017-03-26 18:43:45 +00:00

1737 lines
68 KiB
Diff

------------------------------------------------------------
revno: 3648
fixes bug: https://launchpad.net/bugs/1668892
committer: Tyler Hicks <tyhicks@canonical.com>
branch nick: apparmor
timestamp: Fri 2017-03-24 05:08:01 +0000
message:
utils: Add aa-remove-unknown utility to unload unknown profiles
https://launchpad.net/bugs/1668892
This patch creates a new utility, with the code previously used in the
init script 'restart' action, that removes unknown profiles which are
not found in /etc/apparmor.d/. The functionality was removed from the
common init script code in the fix for CVE-2017-6507.
The new utility prints a message containing the name of each unknown
profile before the profiles are removed. It also supports a dry run mode
so that an administrator can check which profiles will be removed before
unloading any unknown profiles.
If you backport this utility with the fix for CVE-2017-6507 to an
apparmor 2.10 release and your backported aa-remove-unknown utility is
sourcing the upstream rc.apparmor.functions file, you'll want to include
the following bug fix to prevent the aa-remove-unknown utility from
removing child profiles that it shouldn't remove:
r3440 - Fix: parser: incorrect output of child profile names
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
Acked-by: John Johansen <john.johansen@canonical.com>
------------------------------------------------------------
revno: 3647
fixes bug: https://launchpad.net/bugs/1668892
committer: Tyler Hicks <tyhicks@canonical.com>
branch nick: apparmor
timestamp: Fri 2017-03-24 05:06:07 +0000
message:
parser: Preserve unknown profiles when restarting apparmor init/job/unit
CVE-2017-6507
https://launchpad.net/bugs/1668892
The common AppArmor 'restart' code used by some init scripts, upstart
jobs, and/or systemd units contained functionality that is no longer
appropriate to retain. Any profiles not found /etc/apparmor.d/ were
assumed to be obsolete and were unloaded. That behavior became
problematic now that there's a growing number of projects that maintain
their own internal set of AppArmor profiles outside of /etc/apparmor.d/.
It resulted in the AppArmor 'restart' code leaving some important
processes running unconfined. A couple examples are profiles managed by
LXD and Docker.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
Acked-by: John Johansen <john.johansen@canonical.com>
------------------------------------------------------------
revno: 3646
committer: Seth Arnold <seth.arnold@canonical.com>
branch nick: apparmor
timestamp: Tue 2017-03-21 12:09:59 -0700
message:
parser: Fix delete after new[] -- patch from Oleg Strikov <oleg.strikov@gmail.com>
------------------------------------------------------------
revno: 3645 [merge]
committer: Tyler Hicks <tyhicks@canonical.com>
branch nick: apparmor
timestamp: Thu 2017-03-16 02:51:03 +0000
message:
profiles: Update nvidia abstraction for newer nvidia drivers
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Jamie Strandboge <jamie@ubuntu.com>
------------------------------------------------------------
revno: 3644
committer: Christian Boltz <apparmor@cboltz.de>
branch nick: apparmor
timestamp: Fri 2017-03-03 13:14:55 +0100
message:
Fix regressions caused by init_aa()
With the init_aa() patch series commited, minitools_test.py showed
several test failures - which effectively means the -d option of
aa-complain, aa-cleanprof etc. was broken.
These failures were caused by
- calling init_aa() too late in tools.py - _after_ setting the
profiledir, which then got overwritten by init_aa()
- calling init_aa() twice (because apparmor.aa gets imported in two
modules used by aa-cleanprof), which overwrote the manually set values
on the second run
This patch fixes the call order in tools.py and adds a check to
init_aa() so that it only runs once and ignores additional calls.
Acked-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
------------------------------------------------------------
revno: 3643
committer: Christian Boltz <apparmor@cboltz.de>
branch nick: apparmor
timestamp: Fri 2017-03-03 13:14:03 +0100
message:
test-parser-simple-tests.py: No longer skip testing generated_perms_leading profiles
FileRule understands leading permissions, so the reason to skip those
(generated) test profiles in test-parser-simple-tests.py is gone.
However, the gen-xtrans.pl script generates profiles with a not-so-valid
mix of uppercase and lowercase, for example "Pux" and "Cux". The parser
accepts this, but the tools complain about such rules. Therefore add the
affected profiles to the exception list.
In total, this means we now test 319 of the 380 generated_perms_leading
test profiles.
The patch also moves some lines around to get the \-escaped profiles
out of the mixed uppercase/lowercase exec rule section.
Acked-by: Seth Arnold <seth.arnold@canonical.com>
------------------------------------------------------------
revno: 3642
committer: Tyler Hicks <tyhicks@canonical.com>
branch nick: apparmor
timestamp: Thu 2017-03-02 21:25:01 +0000
message:
utils: Fix apparmor.easyprof import in test-aa-easyprof.py
The test-aa-easyprof.py script was attempting to do its own special
setup to import the in-tree easyprof module. However, this proved to be
very flaky and resulted in the test periodically failing due to an
AttributeError the first time easyprof.parse_args() was called.
This patch removes the flakiness by trusting that PYTHONPATH is set up
appropriately before the test script is ran. PYTHONPATH is already
initialized appropriately by utils/test/Makefile according to the
USE_SYSTEM make variable.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
------------------------------------------------------------
revno: 3641
committer: Tyler Hicks <tyhicks@canonical.com>
branch nick: apparmor
timestamp: Thu 2017-03-02 21:24:33 +0000
message:
utils: Set parser executable path according to USE_SYSTEM make variable
if USE_SYSTEM is not set, the utils make check target will instruct
test-aa-easyprof.py to provide the path of the in-tree parser executable
to aa-easyprof.
If USE_SYSTEM is set, the default parser path (/sbin/apparmor_parser or
the result of `which apparmor_parser`) is used.
The test-aa-easyprof.py script receives the parser path by checking the
__AA_PARSER environment variable. This environment variable is strictly
used by the test script and not any user-facing code so two leading
underscores were used.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
------------------------------------------------------------
revno: 3640
committer: Tyler Hicks <tyhicks@canonical.com>
branch nick: apparmor
timestamp: Thu 2017-03-02 21:24:05 +0000
message:
utils: Add option to aa-easyprof to specify the apparmor_parser path
When testing against a clean system without the apparmor_parser binary
installed, the test-aa-easyprof.py script ends up skipping profile
verification because it can't find the parser binary. This even causes a
test failure due to the test_genpolicy_invalid_template_policy test.
Adding a --parser option to aa-easyprof is the first step in addressing
this problem.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
------------------------------------------------------------
revno: 3639
committer: Tyler Hicks <tyhicks@canonical.com>
branch nick: apparmor
timestamp: Thu 2017-03-02 21:23:32 +0000
message:
utils: Set parser base path according to USE_SYSTEM make variable
If USE_SYSTEM is not set, the utils make check target will instruct
test-aa-easyprof.py to provide the path of the in-tree
profiles/apparmor.d directory to aa-easyprof as the parser base
directory.
If USE_SYSTEM is set, the default base directory (/etc/apparmor.d) is
used.
The test-aa-easyprof.py script receives the base path by checking the
__AA_BASEDIR environment variable. This environment variable is strictly
used by the test script and not any user-facing code so two leading
underscores were used.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
------------------------------------------------------------
revno: 3638
fixes bug: https://launchpad.net/bugs/1521031
committer: Tyler Hicks <tyhicks@canonical.com>
branch nick: apparmor
timestamp: Thu 2017-03-02 21:22:57 +0000
message:
utils: Accept parser base and include options in aa-easyprof
https://launchpad.net/bugs/1521031
aa-easyprof accepts a list of abstractions to include and, by default,
execs apparmor_parser to verify the generated profile including any
abstractions. However, aa-easyprof didn't provide the same flexibility
as apparmor_parser when it came to where in the filesystem the
abstraction files could exist.
The parser supports --base (defaulting to /etc/apparmor.d) and --Include
(defaulting to unset) options to specify the search paths for
abstraction files. This patch adds the same options to aa-easyprof to
aide in two different situations:
1) Some Ubuntu packages use aa-easyprof to generate AppArmor profiles
at build time. Something that has been previously needed is a way
for those packages to ship their own abstractions file(s) that are
#included in the easyprof-generated profile. That's not been
possible since the abstraction file(s) have not yet been installed
during the package build.
2) The test-aa-easyprof.py script contains some tests that specify
abstractions that should be #included. Without the ability to
specify a different --base or --Include directory, the abstractions
were required to be present in /etc/apparmor.d/abstractions/ or the
tests would fail. This prevents the Python utils from being able to
strictly test against in-tree code/profiles/etc.
I don't like the names of the command line options --base and --Include.
They're not particularly descriptive and the capital 'I' is not user
friendly. However, I decided to preserve the name of the options from
apparmor_parser.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
------------------------------------------------------------
revno: 3637
committer: Tyler Hicks <tyhicks@canonical.com>
branch nick: apparmor
timestamp: Thu 2017-03-02 21:21:53 +0000
message:
utils: Require apparmor.aa users to call init_aa()
Introduce an apparmor.aa.init_aa() method and move the initialization
code of the apparmor.aa module into it. Note that this change will break
any external users of apparmor.aa because global variables that were
previously initialized when importing apparmor.aa will not be
initialized unless a call to the new apparmor.aa.init_aa() method is
made.
The main purpose of this change is to allow the utils tests to be able
to set a non-default location for configuration files. Instead of
hard-coding the location of logprof.conf and other utils related
configuration files to /etc/apparmor/, this patch allows it to be
configured by calling apparmor.aa.init_aa(confdir=PATH).
This allows for the make check target to use the in-tree config file,
profiles, and parser by default. A helper method, setup_aa(), is added
to common_test.py that checks for an environment variable containing a
non-default configuration directory path prior to calling
apparmor.aa.init_aa(). All test scripts that use apparmor.aa are updated
to call setup_aa().
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Suggested-by: Christian Boltz <apparmor@cboltz.de>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
------------------------------------------------------------
revno: 3636
committer: Tyler Hicks <tyhicks@canonical.com>
branch nick: apparmor
timestamp: Thu 2017-03-02 21:21:21 +0000
message:
utils: Update the logprof.conf in the test dir to point to in-tree paths
The utils tests should make use of the logprof.conf that resides in
utils/test/ when testing against the in-tree parser and profiles. When
testing against the system, it the utils tests should continue to use
the system logprof.conf.
This patch updates the parser and profiles paths to point to the in-tree
paths. Another patch is needed to get aa.py to honor a non-hardcoded
search path for logprof.conf and other configuration files.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
------------------------------------------------------------
revno: 3635
committer: Tyler Hicks <tyhicks@canonical.com>
branch nick: apparmor
timestamp: Thu 2017-03-02 21:20:45 +0000
message:
utils: Improve error messages when profiles/parser is not found
When aa.py is imported, it looks for a set of profiles and it also looks
for the parser. Both of these paths are configured by logprof.conf but
it isn't always obvious which logprof.conf file was used and, therefore,
it isn't always obvious where aa.py is looking. This patch includes the
paths in the error messages.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
------------------------------------------------------------
revno: 3634
fixes bug: https://launchpad.net/bugs/1628286
committer: Tyler Hicks <tyhicks@canonical.com>
branch nick: apparmor
timestamp: Tue 2017-02-28 23:04:24 +0000
message:
utils: Don't enforce ordering of dbus rule attributes
https://launchpad.net/bugs/1628286
The utils were enforcing that the dbus rule attributes were strictly
ordered in the following fashion:
bus -> path -> interface -> member -> peer
However, the parser has always accepted the attributes in any order. If
the system contained a profile which did not use the strict ordering
enforced by the utils, the utils would refuse to operate at all.
This patch eases the restriction on the ordering at the expense of the
utils no longer being able to detect and reject a single attribute that
is repeated multiple times. In that situation, only the last occurrence
of the attribute will be honored by the utils.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
------------------------------------------------------------
revno: 3633
committer: Tyler Hicks <tyhicks@canonical.com>
branch nick: apparmor
timestamp: Tue 2017-02-28 23:03:25 +0000
message:
utils: Fix failing tests in test-aa.py
The merged /usr patches to the policy broke some utils tests due to a
change in the expected output.
Fixes: r3600 update lots of profiles for usrMerge
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
------------------------------------------------------------
revno: 3632
committer: Christian Boltz <apparmor@cboltz.de>
branch nick: apparmor
timestamp: Thu 2017-02-23 01:00:36 +0100
message:
Ignore change_hat events with error=-1 and "unconfined can not change_hat"
That's much better than crashing aa-logprof ;-) (use the log line in
the added testcase if you want to see the crash)
Reported by pfak on IRC.
Acked-by: Seth Arnold <seth.arnold@canonical.com> for trunk, 2.10 and 2.9.
------------------------------------------------------------
revno: 3631
committer: Christian Boltz <apparmor@cboltz.de>
branch nick: apparmor
timestamp: Tue 2017-02-21 18:46:36 +0100
message:
Remove re.LOCALE flag
Starting with python 3.6, the re.LOCALE flag can only be used with byte
patterns, and errors out if used with str. This patch removes the flag
in get_translated_hotkey().
References: https://bugs.launchpad.net/apparmor/+bug/1661766
Acked-by: Steve Beattie <steve@nxnw.org> for trunk, 2.10 and 2.9
------------------------------------------------------------
revno: 3630
committer: Steve Beattie <sbeattie@ubuntu.com>
branch nick: apparmor
timestamp: Wed 2017-02-01 21:41:52 -0800
message:
regression tests: fix environ fail case
In the environ regression test, when the exec() of the child process
fails, we don't report FAIL to stdout, so the regression tests consider
it an error rather than a failure and abort, short-circuiting the
test script.
This commit fixes this by emitting the FAIL message when the result
from the wait() syscall indicates the child process did not succeed.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
------------------------------------------------------------
revno: 3629
committer: Christian Boltz <apparmor@cboltz.de>
branch nick: apparmor
timestamp: Mon 2017-01-30 20:48:50 +0100
message:
Rename global variable "pid" to "log_pid"
aa.py has a global variable "pid", but it also has several functions
that use "pid" as a local variable name. do_logprof_pass() even uses
both - first, it passes the global variable to ReadLog, and then it
creates a local variable in the "for pid in ..." loop.
This patch renames the global variable to log_pid to get rid of the
confusion.
Note that the global variable is only handed over to ReadLog, and the
only case where its previous content _might_ be used is aa-genprof which
does multipe do_logprof_pass() runs.
Maybe we could even get rid of this variable in aa.py and make it local
to the ReadLog class, but I'm not sure if that would affect aa-genprof
in interesting[tm] ways.
Acked-by: John Johansen <john.johansen@canonical.com>
------------------------------------------------------------
Use --include-merged or -n0 to see merged revisions.
=== added file 'libraries/libapparmor/testsuite/test_multi/unconfined-change_hat.err'
=== added file 'libraries/libapparmor/testsuite/test_multi/unconfined-change_hat.in'
--- libraries/libapparmor/testsuite/test_multi/unconfined-change_hat.in 1970-01-01 00:00:00 +0000
+++ libraries/libapparmor/testsuite/test_multi/unconfined-change_hat.in 2017-02-23 00:00:36 +0000
@@ -0,0 +1,1 @@
+Feb 21 23:22:01 mail-20170118 kernel: [1222198.459750] audit: type=1400 audit(1487719321.954:218): apparmor="ALLOWED" operation="change_hat" info="unconfined can not change_hat" error=-1 profile="unconfined" pid=19941 comm="apache2"
=== added file 'libraries/libapparmor/testsuite/test_multi/unconfined-change_hat.out'
--- libraries/libapparmor/testsuite/test_multi/unconfined-change_hat.out 1970-01-01 00:00:00 +0000
+++ libraries/libapparmor/testsuite/test_multi/unconfined-change_hat.out 2017-02-23 00:00:36 +0000
@@ -0,0 +1,12 @@
+START
+File: unconfined-change_hat.in
+Event type: AA_RECORD_ALLOWED
+Audit ID: 1487719321.954:218
+Operation: change_hat
+Profile: unconfined
+Command: apache2
+Info: unconfined can not change_hat
+ErrorCode: 1
+PID: 19941
+Epoch: 1487719321
+Audit subid: 218
=== added file 'libraries/libapparmor/testsuite/test_multi/unconfined-change_hat.profile'
--- libraries/libapparmor/testsuite/test_multi/unconfined-change_hat.profile 1970-01-01 00:00:00 +0000
+++ libraries/libapparmor/testsuite/test_multi/unconfined-change_hat.profile 2017-02-23 00:00:36 +0000
@@ -0,0 +1,2 @@
+profile unconfined {
+}
=== modified file 'parser/libapparmor_re/expr-tree.h'
--- parser/libapparmor_re/expr-tree.h 2016-01-19 23:07:04 +0000
+++ parser/libapparmor_re/expr-tree.h 2017-03-21 19:09:59 +0000
@@ -672,7 +672,7 @@
~hashedNodeVec()
{
- delete nodes;
+ delete [] nodes;
}
unsigned long size()const { return len; }
=== modified file 'parser/rc.apparmor.functions'
--- parser/rc.apparmor.functions 2012-02-24 12:21:59 +0000
+++ parser/rc.apparmor.functions 2017-03-24 05:06:07 +0000
@@ -451,34 +451,7 @@
configure_owlsm
parse_profiles reload
- # Clean out running profiles not associated with the current profile
- # set, excluding the libvirt dynamically generated profiles.
- # Note that we reverse sort the list of profiles to remove to
- # ensure that child profiles (e.g. hats) are removed before the
- # parent. We *do* need to remove the child profile and not rely
- # on removing the parent profile when the profile has had its
- # child profile names changed.
- profiles_names_list | awk '
-BEGIN {
- while (getline < "'${SFS_MOUNTPOINT}'/profiles" ) {
- str = sub(/ \((enforce|complain)\)$/, "", $0);
- if (match($0, /^libvirt-[0-9a-f\-]+$/) == 0)
- arr[$str] = $str
- }
-}
-
-{ if (length(arr[$0]) > 0) { delete arr[$0] } }
-
-END {
- for (key in arr)
- if (length(arr[key]) > 0) {
- printf("%s\n", arr[key])
- }
-}
-' | LC_COLLATE=C sort -r | while IFS= read profile ; do
- echo -n "$profile" > "$SFS_MOUNTPOINT/.remove"
- done
- # will not catch all errors, but still better than nothing
+
rc=$?
aa_log_end_msg $rc
return $rc
=== modified file 'profiles/apparmor.d/abstractions/nvidia'
--- profiles/apparmor.d/abstractions/nvidia 2014-06-06 18:50:58 +0000
+++ profiles/apparmor.d/abstractions/nvidia 2017-03-06 18:59:43 +0000
@@ -8,8 +8,9 @@
/etc/vdpau_wrapper.cfg r,
# device files
- /dev/nvidia0 rw,
- /dev/nvidiactl rw,
+ /dev/nvidiactl rw,
+ /dev/nvidia-modeset rw,
+ /dev/nvidia[0-9]* rw,
@{PROC}/interrupts r,
@{PROC}/sys/vm/max_map_count r,
@@ -18,3 +19,5 @@
owner @{HOME}/.nv/GLCache/ r,
owner @{HOME}/.nv/GLCache/** rwk,
+
+ unix (send, receive) type=dgram peer=(addr="@nvidia[0-9a-f]*"),
=== modified file 'tests/regression/apparmor/environ.c'
--- tests/regression/apparmor/environ.c 2010-12-20 20:29:10 +0000
+++ tests/regression/apparmor/environ.c 2017-02-02 05:41:52 +0000
@@ -63,6 +63,8 @@
if (retval == RET_CHLD_SUCCESS) {
printf("PASS\n");
retval = 0;
+ } else {
+ printf("FAIL: Child failed\n");
}
} else if (pid == 0) {
=== modified file 'utils/Makefile'
--- utils/Makefile 2016-12-10 18:25:31 +0000
+++ utils/Makefile 2017-03-24 05:08:01 +0000
@@ -24,7 +24,7 @@
PYTOOLS = aa-easyprof aa-genprof aa-logprof aa-cleanprof aa-mergeprof \
aa-autodep aa-audit aa-complain aa-enforce aa-disable \
aa-status aa-unconfined
-TOOLS = ${PERLTOOLS} ${PYTOOLS} aa-decode
+TOOLS = ${PERLTOOLS} ${PYTOOLS} aa-decode aa-remove-unknown
PYSETUP = python-tools-setup.py
PYMODULES = $(wildcard apparmor/*.py apparmor/rule/*.py)
=== modified file 'utils/aa-easyprof.pod'
--- utils/aa-easyprof.pod 2015-03-27 21:33:35 +0000
+++ utils/aa-easyprof.pod 2017-03-02 21:24:05 +0000
@@ -57,6 +57,12 @@
AppArmor rules or policies. They are similar to AppArmor abstractions, but
usually encompass more policy rules.
+=item --parser PATH
+
+Specify the PATH of the apparmor_parser binary to use when verifying
+policy. If this option is not specified, aa-easyprof will attempt to
+locate the path starting with /sbin/apparmor_parser.
+
=item -a ABSTRACTIONS, --abstractions=ABSTRACTIONS
Specify ABSTRACTIONS as a comma-separated list of AppArmor abstractions. It is
@@ -64,6 +70,16 @@
convenience. AppArmor abstractions are located in /etc/apparmor.d/abstractions.
See apparmor.d(5) for details.
+=item -b PATH, --base=PATH
+
+Set the base PATH for resolving abstractions specified by --abstractions.
+See the same option in apparmor_parser(8) for details.
+
+=item -I PATH, --Include=PATH
+
+Add PATH to the search paths used for resolving abstractions specified by
+--abstractions. See the same option in apparmor_parser(8) for details.
+
=item -r PATH, --read-path=PATH
Specify a PATH to allow owner reads. May be specified multiple times. If the
=== modified file 'utils/aa-genprof'
--- utils/aa-genprof 2016-10-01 18:57:09 +0000
+++ utils/aa-genprof 2017-03-02 21:21:53 +0000
@@ -66,6 +66,7 @@
profiling = args.program
profiledir = args.dir
+apparmor.init_aa()
apparmor.set_logfile(args.file)
aa_mountpoint = apparmor.check_for_apparmor()
=== modified file 'utils/aa-logprof'
--- utils/aa-logprof 2016-10-01 18:57:09 +0000
+++ utils/aa-logprof 2017-03-02 21:21:53 +0000
@@ -34,6 +34,7 @@
profiledir = args.dir
logmark = args.mark or ''
+apparmor.init_aa()
apparmor.set_logfile(args.file)
aa_mountpoint = apparmor.check_for_apparmor()
=== modified file 'utils/aa-mergeprof'
--- utils/aa-mergeprof 2017-01-19 15:54:47 +0000
+++ utils/aa-mergeprof 2017-03-02 21:21:53 +0000
@@ -43,6 +43,8 @@
args.other = None
+apparmor.aa.init_aa()
+
profiles = args.files
profiledir = args.dir
=== added file 'utils/aa-remove-unknown'
--- utils/aa-remove-unknown 1970-01-01 00:00:00 +0000
+++ utils/aa-remove-unknown 2017-03-24 05:08:01 +0000
@@ -0,0 +1,108 @@
+#!/bin/sh
+# ----------------------------------------------------------------------
+# Copyright (c) 2017 Canonical Ltd. (All rights reserved)
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of version 2 of the GNU General Public
+# License published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# ----------------------------------------------------------------------
+
+APPARMOR_FUNCTIONS=/lib/apparmor/rc.apparmor.functions
+APPARMORFS=/sys/kernel/security/apparmor
+PROFILES="${APPARMORFS}/profiles"
+REMOVE="${APPARMORFS}/.remove"
+
+DRY_RUN=0
+
+. $APPARMOR_FUNCTIONS
+
+usage() {
+ local progname="$1"
+ local rc="$2"
+ local msg="usage: ${progname} [options]\n
+Remove profiles unknown to the system
+
+Options:
+ -h, --help Show this help message and exit
+ -n Dry run; don't remove profiles"
+
+ if [ "$rc" -ne 0 ] ; then
+ echo "$msg" 1>&2
+ else
+ echo "$msg"
+ fi
+
+ exit "$rc"
+}
+
+if [ "$#" -gt 1 ] ; then
+ usage "$0" 1
+elif [ "$#" -eq 1 ] ; then
+ if [ "$1" = "-h" -o "$1" = "--help" ] ; then
+ usage "$0" 0
+ elif [ "$1" = "-n" ] ; then
+ DRY_RUN=1
+ else
+ usage "$0" 1
+ fi
+fi
+
+
+# We can't use a -r test here because while $PROFILES is world-readable,
+# apparmorfs may still return EACCES from open()
+#
+# We have to do this check because error checking awk's getline() below is
+# tricky and, as is, results in an infinite loop when apparmorfs returns an
+# error from open().
+if ! IFS= read line < "$PROFILES" ; then
+ echo "ERROR: Unable to read apparmorfs profiles file" 1>&2
+ exit 1
+elif [ ! -w "$REMOVE" ] ; then
+ echo "ERROR: Unable to write to apparmorfs remove file" 1>&2
+ exit 1
+fi
+
+# Clean out running profiles not associated with the current profile
+# set, excluding the libvirt dynamically generated profiles.
+# Note that we reverse sort the list of profiles to remove to
+# ensure that child profiles (e.g. hats) are removed before the
+# parent. We *do* need to remove the child profile and not rely
+# on removing the parent profile when the profile has had its
+# child profile names changed.
+profiles_names_list | awk '
+BEGIN {
+ while (getline < "'${PROFILES}'" ) {
+ str = sub(/ \((enforce|complain)\)$/, "", $0);
+ if (match($0, /^libvirt-[0-9a-f\-]+$/) == 0)
+ arr[$str] = $str
+ }
+}
+
+{ if (length(arr[$0]) > 0) { delete arr[$0] } }
+
+END {
+ for (key in arr)
+ if (length(arr[key]) > 0) {
+ printf("%s\n", arr[key])
+ }
+}
+' | LC_COLLATE=C sort -r | \
+ while IFS= read profile ; do
+ if [ "$DRY_RUN" -ne 0 ]; then
+ echo "Would remove '${profile}'"
+ else
+ echo "Removing '${profile}'"
+ echo -n "$profile" > "${REMOVE}"
+ fi
+ done
+
+# will not catch all errors, but still better than nothing
+exit $?
=== added file 'utils/aa-remove-unknown.pod'
--- utils/aa-remove-unknown.pod 1970-01-01 00:00:00 +0000
+++ utils/aa-remove-unknown.pod 2017-03-24 05:08:01 +0000
@@ -0,0 +1,51 @@
+=pod
+
+=head1 NAME
+
+aa-remove-unknown - remove unknown AppArmor profiles
+
+=head1 SYNOPSIS
+
+B<aa-remove-unknown> [option]
+
+=head1 DESCRIPTION
+
+B<aa-remove-unknown> will inventory all profiles in /etc/apparmor.d/, compare
+that list to the profiles currently loaded into the kernel, and then remove all
+of the loaded profiles that were not found in /etc/apparmor.d/. It will also
+report the name of each profile that it removes on standard out.
+
+=head1 OPTIONS
+
+=over 4
+
+=item -h, --help
+
+displays a short usage statement.
+
+=item -n
+
+dry run; only prints the names of profiles that would be removed
+
+=back
+
+=head1 EXAMPLES
+
+ $ sudo ./aa-remove-unknown -n
+ Would remove 'test//null-/usr/bin/whoami'
+ Would remove 'test'
+
+ $ sudo ./aa-remove-unknown
+ Removing 'test//null-/usr/bin/whoami'
+ Removing 'test'
+
+=head1 BUGS
+
+None. Please report any you find to Launchpad at
+L<https://bugs.launchpad.net/apparmor/+filebug>.
+
+=head1 SEE ALSO
+
+apparmor(7)
+
+=cut
=== modified file 'utils/aa-unconfined'
--- utils/aa-unconfined 2016-12-30 20:22:58 +0000
+++ utils/aa-unconfined 2017-03-02 21:21:53 +0000
@@ -40,6 +40,7 @@
paranoid = args.paranoid
+aa.init_aa()
aa_mountpoint = aa.check_for_apparmor()
if not aa_mountpoint:
raise aa.AppArmorException(_("It seems AppArmor was not started. Please enable AppArmor and try again."))
=== modified file 'utils/apparmor/aa.py'
--- utils/apparmor/aa.py 2017-01-20 00:20:41 +0000
+++ utils/apparmor/aa.py 2017-03-03 12:14:55 +0000
@@ -73,14 +73,14 @@
# Setup logging incase of debugging is enabled
debug_logger = DebugLogger('aa')
-CONFDIR = '/etc/apparmor'
-
# The database for severity
sev_db = None
# The file to read log messages from
### Was our
logfile = None
+CONFDIR = None
+conf = None
cfg = None
repo_cfg = None
@@ -105,7 +105,7 @@
extras = hasher() # Inactive profiles from extras
### end our
log = []
-pid = dict()
+log_pid = dict() # handed over to ReadLog, gets filled in logparser.py. The only case the previous content of this variable _might_(?) be used is aa-genprof (multiple do_logprof_pass() runs)
profile_changes = hasher()
prelog = hasher()
@@ -1857,7 +1857,7 @@
elif os.path.isdir(logfile):
raise AppArmorException(_('%s is a directory. Please specify a file as logfile') % logfile)
-def do_logprof_pass(logmark='', passno=0, pid=pid):
+def do_logprof_pass(logmark='', passno=0, log_pid=log_pid):
# set up variables for this pass
# transitions = hasher()
global log
@@ -1885,7 +1885,7 @@
## if not repo_cfg['repository'].get('enabled', False) or repo_cfg['repository]['enabled'] not in ['yes', 'no']:
## UI_ask_to_enable_repo()
- log_reader = apparmor.logparser.ReadLog(pid, logfile, existing_profiles, profile_dir, log)
+ log_reader = apparmor.logparser.ReadLog(log_pid, logfile, existing_profiles, profile_dir, log)
log = log_reader.read_log(logmark)
#read_log(logmark)
@@ -3741,24 +3741,36 @@
######Initialisations######
-conf = apparmor.config.Config('ini', CONFDIR)
-cfg = conf.read_config('logprof.conf')
-
-# prevent various failures if logprof.conf doesn't exist
-if not cfg.sections():
- cfg.add_section('settings')
- cfg.add_section('required_hats')
-
-if cfg['settings'].get('default_owner_prompt', False):
- cfg['settings']['default_owner_prompt'] = ''
-
-profile_dir = conf.find_first_dir(cfg['settings'].get('profiledir')) or '/etc/apparmor.d'
-if not os.path.isdir(profile_dir):
- raise AppArmorException('Can\'t find AppArmor profiles')
-
-extra_profile_dir = conf.find_first_dir(cfg['settings'].get('inactive_profiledir')) or '/usr/share/apparmor/extra-profiles/'
-
-parser = conf.find_first_file(cfg['settings'].get('parser')) or '/sbin/apparmor_parser'
-if not os.path.isfile(parser) or not os.access(parser, os.EX_OK):
- raise AppArmorException('Can\'t find apparmor_parser')
+def init_aa(confdir="/etc/apparmor"):
+ global CONFDIR
+ global conf
+ global cfg
+ global profile_dir
+ global extra_profile_dir
+ global parser
+
+ if CONFDIR:
+ return # config already initialized (and possibly changed afterwards), so don't overwrite the config variables
+
+ CONFDIR = confdir
+ conf = apparmor.config.Config('ini', CONFDIR)
+ cfg = conf.read_config('logprof.conf')
+
+ # prevent various failures if logprof.conf doesn't exist
+ if not cfg.sections():
+ cfg.add_section('settings')
+ cfg.add_section('required_hats')
+
+ if cfg['settings'].get('default_owner_prompt', False):
+ cfg['settings']['default_owner_prompt'] = ''
+
+ profile_dir = conf.find_first_dir(cfg['settings'].get('profiledir')) or '/etc/apparmor.d'
+ if not os.path.isdir(profile_dir):
+ raise AppArmorException('Can\'t find AppArmor profiles in %s' % (profile_dir))
+
+ extra_profile_dir = conf.find_first_dir(cfg['settings'].get('inactive_profiledir')) or '/usr/share/apparmor/extra-profiles/'
+
+ parser = conf.find_first_file(cfg['settings'].get('parser')) or '/sbin/apparmor_parser'
+ if not os.path.isfile(parser) or not os.access(parser, os.EX_OK):
+ raise AppArmorException('Can\'t find apparmor_parser at %s' % (parser))
=== modified file 'utils/apparmor/cleanprofile.py'
--- utils/apparmor/cleanprofile.py 2016-10-01 17:54:48 +0000
+++ utils/apparmor/cleanprofile.py 2017-03-02 21:21:53 +0000
@@ -16,6 +16,7 @@
class Prof(object):
def __init__(self, filename):
+ apparmor.init_aa()
self.aa = apparmor.aa
self.filelist = apparmor.filelist
self.include = apparmor.include
=== modified file 'utils/apparmor/easyprof.py'
--- utils/apparmor/easyprof.py 2015-03-28 12:16:22 +0000
+++ utils/apparmor/easyprof.py 2017-03-02 21:24:05 +0000
@@ -259,14 +259,11 @@
return orig
-def verify_policy(policy):
+def verify_policy(policy, exe, base=None, include=None):
'''Verify policy compiles'''
- exe = "/sbin/apparmor_parser"
- if not os.path.exists(exe):
- rc, exe = cmd(['which', 'apparmor_parser'])
- if rc != 0:
- warn("Could not find apparmor_parser. Skipping verify")
- return True
+ if not exe:
+ warn("Could not find apparmor_parser. Skipping verify")
+ return True
fn = ""
# if policy starts with '/' and is one line, assume it is a path
@@ -279,7 +276,14 @@
os.write(f, policy)
os.close(f)
- rc, out = cmd([exe, '-QTK', fn])
+ command = [exe, '-QTK']
+ if base:
+ command.extend(['-b', base])
+ if include:
+ command.extend(['-I', include])
+ command.append(fn)
+
+ rc, out = cmd(command)
os.unlink(fn)
if rc == 0:
return True
@@ -302,6 +306,22 @@
if os.path.isfile(self.conffile):
self._get_defaults()
+ self.parser_path = '/sbin/apparmor_parser'
+ if opt.parser_path:
+ self.parser_path = opt.parser_path
+ elif not os.path.exists(self.parser_path):
+ rc, self.parser_path = cmd(['which', 'apparmor_parser'])
+ if rc != 0:
+ self.parser_path = None
+
+ self.parser_base = "/etc/apparmor.d"
+ if opt.parser_base:
+ self.parser_base = opt.parser_base
+
+ self.parser_include = None
+ if opt.parser_include:
+ self.parser_include = opt.parser_include
+
if opt.templates_dir and os.path.isdir(opt.templates_dir):
self.dirs['templates'] = os.path.abspath(opt.templates_dir)
elif not opt.templates_dir and \
@@ -350,8 +370,6 @@
if not 'policygroups' in self.dirs:
raise AppArmorException("Could not find policygroups directory")
- self.aa_topdir = "/etc/apparmor.d"
-
self.binary = binary
if binary:
if not valid_binary_path(binary):
@@ -506,9 +524,15 @@
def gen_abstraction_rule(self, abstraction):
'''Generate an abstraction rule'''
- p = os.path.join(self.aa_topdir, "abstractions", abstraction)
- if not os.path.exists(p):
- raise AppArmorException("%s does not exist" % p)
+ base = os.path.join(self.parser_base, "abstractions", abstraction)
+ if not os.path.exists(base):
+ if not self.parser_include:
+ raise AppArmorException("%s does not exist" % base)
+
+ include = os.path.join(self.parser_include, "abstractions", abstraction)
+ if not os.path.exists(include):
+ raise AppArmorException("Neither %s nor %s exist" % (base, include))
+
return "#include <abstractions/%s>" % abstraction
def gen_variable_declaration(self, dec):
@@ -661,7 +685,7 @@
if no_verify:
debug("Skipping policy verification")
- elif not verify_policy(policy):
+ elif not verify_policy(policy, self.parser_path, self.parser_base, self.parser_include):
msg("\n" + policy)
raise AppArmorException("Invalid policy")
@@ -804,6 +828,10 @@
def add_parser_policy_args(parser):
'''Add parser arguments'''
+ parser.add_option("--parser",
+ dest="parser_path",
+ help="The path to the profile parser used for verification",
+ metavar="PATH")
parser.add_option("-a", "--abstractions",
action="callback",
callback=check_for_manifest_arg,
@@ -811,6 +839,14 @@
dest="abstractions",
help="Comma-separated list of abstractions",
metavar="ABSTRACTIONS")
+ parser.add_option("-b", "--base",
+ dest="parser_base",
+ help="Set the base directory for resolving abstractions",
+ metavar="DIR")
+ parser.add_option("-I", "--Include",
+ dest="parser_include",
+ help="Add a directory to the search path when resolving abstractions",
+ metavar="DIR")
parser.add_option("--read-path",
action="callback",
callback=check_for_manifest_arg_append,
=== modified file 'utils/apparmor/logparser.py'
--- utils/apparmor/logparser.py 2016-12-06 21:24:56 +0000
+++ utils/apparmor/logparser.py 2017-02-23 00:00:36 +0000
@@ -243,6 +243,8 @@
if e['operation'] == 'change_hat':
if aamode != 'HINT' and aamode != 'PERMITTING':
return None
+ if e['error_code'] == 1 and e['info'] == 'unconfined can not change_hat':
+ return None
profile = e['name2']
#hat = None
if '//' in e['name2']:
=== modified file 'utils/apparmor/rule/dbus.py'
--- utils/apparmor/rule/dbus.py 2016-10-01 18:08:10 +0000
+++ utils/apparmor/rule/dbus.py 2017-02-28 23:04:24 +0000
@@ -37,14 +37,16 @@
RE_FLAG = '(?P<%s>(\S+|"[^"]+"|\(\s*\S+\s*\)|\(\s*"[^"]+"\)\s*))' # string without spaces, or quoted string, optionally wrapped in (...). %s is the match group name
# plaintext version: | * | "* " | ( * ) | ( " * " ) |
+# XXX this regex will allow repeated parameters, last one wins
+# XXX (the parser will reject such rules)
RE_DBUS_DETAILS = re.compile(
'^' +
'(\s+(?P<access>' + RE_ACCESS_KEYWORDS + '))?' + # optional access keyword(s)
- '(\s+(bus\s*=\s*' + RE_FLAG % 'bus' + '))?' + # optional bus= system | session | AARE, (...) optional
- '(\s+(path\s*=\s*' + RE_FLAG % 'path' + '))?' + # optional path=AARE, (...) optional
- '(\s+(name\s*=\s*' + RE_FLAG % 'name' + '))?' + # optional name=AARE, (...) optional
- '(\s+(interface\s*=\s*' + RE_FLAG % 'interface' + '))?' + # optional interface=AARE, (...) optional
- '(\s+(member\s*=\s*' + RE_FLAG % 'member' + '))?' + # optional member=AARE, (...) optional
+ '((\s+(bus\s*=\s*' + RE_FLAG % 'bus' + '))?|' + # optional bus= system | session | AARE, (...) optional
+ '(\s+(path\s*=\s*' + RE_FLAG % 'path' + '))?|' + # optional path=AARE, (...) optional
+ '(\s+(name\s*=\s*' + RE_FLAG % 'name' + '))?|' + # optional name=AARE, (...) optional
+ '(\s+(interface\s*=\s*' + RE_FLAG % 'interface' + '))?|' + # optional interface=AARE, (...) optional
+ '(\s+(member\s*=\s*' + RE_FLAG % 'member' + '))?|' + # optional member=AARE, (...) optional
'(\s+(peer\s*=\s*\((,|\s)*' + # optional peer=( name=AARE and/or label=AARE ), (...) required
'(' +
'(' + '(,|\s)*' + ')' + # empty peer=()
@@ -57,7 +59,7 @@
'|' # or
'(' + 'label\s*=\s*' + RE_PROFILE_NAME % 'peerlabel3' + '(,|\s)+' + 'name\s*=\s*' + RE_PROFILE_NAME % 'peername3' + ')' + # peer label + name (match name peername3/peerlabel3)
')'
- '(,|\s)*\)))?'
+ '(,|\s)*\)))?){0,6}'
'\s*$')
=== modified file 'utils/apparmor/tools.py'
--- utils/apparmor/tools.py 2015-06-06 12:31:03 +0000
+++ utils/apparmor/tools.py 2017-03-03 12:14:55 +0000
@@ -24,6 +24,8 @@
class aa_tools:
def __init__(self, tool_name, args):
+ apparmor.init_aa()
+
self.name = tool_name
self.profiledir = args.dir
self.profiling = args.program
=== modified file 'utils/apparmor/ui.py'
--- utils/apparmor/ui.py 2016-10-03 19:01:29 +0000
+++ utils/apparmor/ui.py 2017-02-21 17:46:36 +0000
@@ -64,8 +64,8 @@
msg = 'PromptUser: ' + _('Invalid hotkey for')
# Originally (\S) was used but with translations it would not work :(
- if re.search('\((\S+)\)', translated, re.LOCALE):
- return re.search('\((\S+)\)', translated, re.LOCALE).groups()[0]
+ if re.search('\((\S+)\)', translated):
+ return re.search('\((\S+)\)', translated).groups()[0]
else:
if cmsg:
raise AppArmorException(cmsg)
=== modified file 'utils/test/Makefile'
--- utils/test/Makefile 2016-05-10 12:31:25 +0000
+++ utils/test/Makefile 2017-03-02 21:24:33 +0000
@@ -23,11 +23,17 @@
ifdef USE_SYSTEM
LD_LIBRARY_PATH=
PYTHONPATH=
+ CONFDIR=
+ BASEDIR=
+ PARSER=
else
# PYTHON_DIST_BUILD_PATH based on libapparmor/swig/python/test/Makefile.am
PYTHON_DIST_BUILD_PATH = ../../libraries/libapparmor/swig/python/build/$$($(PYTHON) -c "import distutils.util; import platform; print(\"lib.%s-%s\" %(distutils.util.get_platform(), platform.python_version()[:3]))")
LD_LIBRARY_PATH=../../libraries/libapparmor/src/.libs/
PYTHONPATH=..:$(PYTHON_DIST_BUILD_PATH)
+ CONFDIR=$(CURDIR)
+ BASEDIR=../../profiles/apparmor.d
+ PARSER=../../parser/apparmor_parser
endif
.PHONY: __libapparmor
@@ -62,10 +68,10 @@
rm -rf __pycache__/ .coverage htmlcov
check: __libapparmor
- export PYTHONPATH=$(PYTHONPATH) ; export LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) ; export LC_ALL=C; $(foreach test, $(wildcard test-*.py), echo ; echo === $(test) === ; $(call pyalldo, $(test)))
+ export PYTHONPATH=$(PYTHONPATH) LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) LC_ALL=C __AA_CONFDIR=$(CONFDIR) __AA_BASEDIR=$(BASEDIR) __AA_PARSER=$(PARSER) ; $(foreach test, $(wildcard test-*.py), echo ; echo === $(test) === ; $(call pyalldo, $(test)))
.coverage: $(wildcard ../aa-* ../apparmor/*.py test-*.py) __libapparmor
- export PYTHONPATH=$(PYTHONPATH) ; export LD_LIBRARY_PATH=$(LD_LIBRARY_PATH); export LC_ALL=C; $(COVERAGE_IGNORE_FAILURES_CMD) ; $(foreach test, $(wildcard test-*.py), echo ; echo === $(test) === ; $(PYTHON) -m coverage run --branch -p $(test); )
+ export PYTHONPATH=$(PYTHONPATH) LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) LC_ALL=C __AA_CONFDIR=$(CONFDIR) __AA_BASEDIR=$(BASEDIR) __AA_PARSER=$(PARSER) ; $(COVERAGE_IGNORE_FAILURES_CMD) ; $(foreach test, $(wildcard test-*.py), echo ; echo === $(test) === ; $(PYTHON) -m coverage run --branch -p $(test); )
$(PYTHON) -m coverage combine
coverage: .coverage
=== modified file 'utils/test/common_test.py'
--- utils/test/common_test.py 2016-05-23 21:15:19 +0000
+++ utils/test/common_test.py 2017-03-02 21:21:53 +0000
@@ -103,6 +103,17 @@
stub_test.__doc__ = "test '%s': %s" % (line, desc)
setattr(test_class, 'test_%d' % (i), stub_test)
+def setup_aa(aa):
+ confdir = os.getenv('__AA_CONFDIR')
+ try:
+ if confdir:
+ aa.init_aa(confdir=confdir)
+ else:
+ aa.init_aa()
+ except AttributeError:
+ # apparmor.aa module versions <= 2.11 do not have the init_aa() method
+ pass
+
def write_file(directory, file, contents):
'''construct path, write contents to it, and return the constructed path'''
path = os.path.join(directory, file)
=== modified file 'utils/test/logprof.conf'
--- utils/test/logprof.conf 2014-08-21 00:14:24 +0000
+++ utils/test/logprof.conf 2017-03-02 21:21:21 +0000
@@ -10,11 +10,11 @@
# ------------------------------------------------------------------
[settings]
- profiledir = /etc/apparmor.d /etc/subdomain.d
- inactive_profiledir = /usr/share/doc/apparmor-profiles/extras
+ profiledir = ../../profiles/apparmor.d
+ inactive_profiledir = ../../profiles/apparmor/profiles/extra
logfiles = /var/log/audit/audit.log /var/log/syslog /var/log/messages
- parser = /sbin/apparmor_parser /sbin/subdomain_parser
+ parser = ../../parser/apparmor_parser
ldd = /usr/bin/ldd
logger = /bin/logger /usr/bin/logger
=== modified file 'utils/test/minitools_test.py'
--- utils/test/minitools_test.py 2015-06-26 23:29:46 +0000
+++ utils/test/minitools_test.py 2017-03-02 21:21:53 +0000
@@ -16,7 +16,7 @@
import subprocess
import sys
import unittest
-from common_test import AATest, setup_all_loops
+from common_test import AATest, setup_all_loops, setup_aa
import apparmor.aa as apparmor
from common_test import read_file
@@ -156,6 +156,7 @@
self.assertEqual(exp_content, real_content, 'Failed to cleanup profile properly')
+setup_aa(apparmor)
setup_all_loops(__name__)
if __name__ == '__main__':
unittest.main(verbosity=2)
=== modified file 'utils/test/test-aa-easyprof.py'
--- utils/test/test-aa-easyprof.py 2016-10-01 18:57:09 +0000
+++ utils/test/test-aa-easyprof.py 2017-03-02 21:25:01 +0000
@@ -18,6 +18,8 @@
import tempfile
import unittest
+import apparmor.easyprof as easyprof
+
topdir = None
debugging = False
@@ -163,6 +165,23 @@
self.binary = "/opt/bin/foo"
self.full_args = ['-c', self.conffile, self.binary]
+ # Check __AA_BASEDIR, which may be set by the Makefile, to see if
+ # we should use a non-default base directory path to find
+ # abstraction files
+ #
+ # NOTE: Individual tests can append another --base path to the
+ # args list and override a base path set here
+ base = os.getenv('__AA_BASEDIR')
+ if base:
+ self.full_args.append('--base=%s' % base)
+
+ # Check __AA_PARSER, which may be set by the Makefile, to see if
+ # we should use a non-default apparmor_parser path to verify
+ # policy
+ parser = os.getenv('__AA_PARSER')
+ if parser:
+ self.full_args.append('--parser=%s' % parser)
+
if debugging:
self.full_args.append('-d')
@@ -913,6 +932,94 @@
raise
raise Exception ("abstraction '%s' should be invalid" % s)
+ def _create_tmp_base_dir(self, prefix='', abstractions=[], tunables=[]):
+ '''Create a temporary base dir layout'''
+ base_name = 'apparmor.d'
+ if prefix:
+ base_name = '%s-%s' % (prefix, base_name)
+ base_dir = os.path.join(self.tmpdir, base_name)
+ abstractions_dir = os.path.join(base_dir, 'abstractions')
+ tunables_dir = os.path.join(base_dir, 'tunables')
+
+ os.mkdir(base_dir)
+ os.mkdir(abstractions_dir)
+ os.mkdir(tunables_dir)
+
+ for f in abstractions:
+ contents = '''
+ # Abstraction file for testing
+ /%s r,
+''' % (f)
+ open(os.path.join(abstractions_dir, f), 'w').write(contents)
+
+ for f in tunables:
+ contents = '''
+# Tunable file for testing
+@{AA_TEST_%s}=foo
+''' % (f)
+ open(os.path.join(tunables_dir, f), 'w').write(contents)
+
+ return base_dir
+
+ def test_genpolicy_abstractions_custom_base(self):
+ '''Test genpolicy (custom base dir)'''
+ abstraction = "custom-base-dir-test-abstraction"
+ # The default template #includes the base abstraction and global
+ # tunable so we need to create placeholders
+ base = self._create_tmp_base_dir(abstractions=['base', abstraction], tunables=['global'])
+ args = ['--abstractions=%s' % abstraction, '--base=%s' % base]
+
+ p = self._gen_policy(extra_args=args)
+ search = "#include <abstractions/%s>" % abstraction
+ self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p))
+ inv_s = '###ABSTRACTIONS###'
+ self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p))
+
+ def test_genpolicy_abstractions_custom_base_bad(self):
+ '''Test genpolicy (custom base dir - bad base dirs)'''
+ abstraction = "custom-base-dir-test-abstraction"
+ bad = [ None, '/etc/apparmor.d', '/' ]
+ for base in bad:
+ try:
+ args = ['--abstractions=%s' % abstraction]
+ if base:
+ args.append('--base=%s' % base)
+ self._gen_policy(extra_args=args)
+ except easyprof.AppArmorException:
+ continue
+ except Exception:
+ raise
+ raise Exception ("abstraction '%s' should be invalid" % abstraction)
+
+ def test_genpolicy_abstractions_custom_include(self):
+ '''Test genpolicy (custom include dir)'''
+ abstraction = "custom-include-dir-test-abstraction"
+ # No need to create placeholders for the base abstraction or global
+ # tunable since we're not adjusting the base directory
+ include = self._create_tmp_base_dir(abstractions=[abstraction])
+ args = ['--abstractions=%s' % abstraction, '--Include=%s' % include]
+ p = self._gen_policy(extra_args=args)
+ search = "#include <abstractions/%s>" % abstraction
+ self.assertTrue(search in p, "Could not find '%s' in:\n%s" % (search, p))
+ inv_s = '###ABSTRACTIONS###'
+ self.assertFalse(inv_s in p, "Found '%s' in :\n%s" % (inv_s, p))
+
+ def test_genpolicy_abstractions_custom_include_bad(self):
+ '''Test genpolicy (custom include dir - bad include dirs)'''
+ abstraction = "custom-include-dir-test-abstraction"
+ bad = [ None, '/etc/apparmor.d', '/' ]
+ for include in bad:
+ try:
+ args = ['--abstractions=%s' % abstraction]
+ if include:
+ args.append('--Include=%s' % include)
+ self._gen_policy(extra_args=args)
+ except easyprof.AppArmorException:
+ continue
+ except Exception:
+ raise
+ raise Exception ("abstraction '%s' should be invalid" % abstraction)
+
def test_genpolicy_profile_name_bad(self):
'''Test genpolicy (profile name - bad values)'''
bad = [
@@ -2568,40 +2675,16 @@
# Main
#
if __name__ == '__main__':
- def cleanup(files):
- for f in files:
- if os.path.exists(f):
- os.unlink(f)
-
absfn = os.path.abspath(sys.argv[0])
topdir = os.path.dirname(os.path.dirname(absfn))
if len(sys.argv) > 1 and (sys.argv[1] == '-d' or sys.argv[1] == '--debug'):
debugging = True
- created = []
-
- # Create the necessary files to import aa-easyprof
- init = os.path.join(os.path.dirname(absfn), '__init__.py')
- if not os.path.exists(init):
- open(init, 'a').close()
- created.append(init)
-
- symlink = os.path.join(os.path.dirname(absfn), 'easyprof.py')
- if not os.path.exists(symlink):
- os.symlink(os.path.join(topdir, 'apparmor', 'easyprof.py'), symlink)
- created.append(symlink)
- created.append(symlink + 'c')
-
- # Now that we have everything we need, import aa-easyprof
- import easyprof
-
# run the tests
suite = unittest.TestSuite()
suite.addTest(unittest.TestLoader().loadTestsFromTestCase(T))
rc = unittest.TextTestRunner(verbosity=2).run(suite)
- cleanup(created)
-
if not rc.wasSuccessful():
sys.exit(1)
=== modified file 'utils/test/test-aa.py'
--- utils/test/test-aa.py 2016-12-30 23:48:41 +0000
+++ utils/test/test-aa.py 2017-03-02 21:21:53 +0000
@@ -10,7 +10,7 @@
# ------------------------------------------------------------------
import unittest
-from common_test import AATest, setup_all_loops
+from common_test import AATest, setup_all_loops, setup_aa
from common_test import read_file, write_file
import os
@@ -784,8 +784,8 @@
('/dev/null', {'allow': {'all': {'r', 'w', 'k'}, 'owner': set() }, 'deny': {'all':set(), 'owner': set()}, 'paths': {'/dev/null'} }),
('/foo/bar', {'allow': {'all': {'r', 'w'}, 'owner': set() }, 'deny': {'all':set(), 'owner': set()}, 'paths': {'/foo/bar'} }), # exec perms not included
('/no/thing', {'allow': {'all': set(), 'owner': set() }, 'deny': {'all':set(), 'owner': set()}, 'paths': set() }),
- ('/usr/lib/ispell/', {'allow': {'all': {'r'}, 'owner': set() }, 'deny': {'all':set(), 'owner': set()}, 'paths': {'/usr/lib/ispell/', '/usr/lib{,32,64}/**'} }), # from abstractions/enchant
- ('/usr/lib/aspell/*.so', {'allow': {'all': {'m', 'r'}, 'owner': set() }, 'deny': {'all':set(), 'owner': set()}, 'paths': {'/usr/lib/aspell/*', '/usr/lib/aspell/*.so', '/usr/lib{,32,64}/**'} }), # from abstractions/aspell via abstractions/enchant
+ ('/usr/lib/ispell/', {'allow': {'all': {'r'}, 'owner': set() }, 'deny': {'all':set(), 'owner': set()}, 'paths': {'/usr/lib/ispell/', '/{usr/,}lib{,32,64}/**'} }), # from abstractions/enchant
+ ('/usr/lib/aspell/*.so', {'allow': {'all': {'m', 'r'}, 'owner': set() }, 'deny': {'all':set(), 'owner': set()}, 'paths': {'/usr/lib/aspell/*', '/usr/lib/aspell/*.so', '/{usr/,}lib{,32,64}/**'} }), # from abstractions/aspell via abstractions/enchant
]
def _run_test(self, params, expected):
@@ -820,8 +820,8 @@
(['/usr/share/common-licenses/foo/bar', 'w'], ['/usr/share/common*/foo/* rw,', '/usr/share/common-licenses/** rw,', '/usr/share/common-licenses/foo/bar rw,'] ),
(['/dev/null', 'wk'], ['/dev/null rwk,'] ),
(['/foo/bar', 'rw'], ['/foo/bar rw,'] ),
- (['/usr/lib/ispell/', 'w'], ['/usr/lib{,32,64}/** rw,', '/usr/lib/ispell/ rw,'] ),
- (['/usr/lib/aspell/some.so', 'k'], ['/usr/lib/aspell/* mrk,', '/usr/lib/aspell/*.so mrk,', '/usr/lib{,32,64}/** mrk,', '/usr/lib/aspell/some.so mrk,'] ),
+ (['/usr/lib/ispell/', 'w'], ['/{usr/,}lib{,32,64}/** rw,', '/usr/lib/ispell/ rw,'] ),
+ (['/usr/lib/aspell/some.so', 'k'], ['/usr/lib/aspell/* mrk,', '/usr/lib/aspell/*.so mrk,', '/{usr/,}lib{,32,64}/** mrk,', '/usr/lib/aspell/some.so mrk,'] ),
]
def _run_test(self, params, expected):
@@ -855,6 +855,7 @@
proposals = propose_file_rules(profile, rule_obj)
self.assertEqual(proposals, expected)
+setup_aa(apparmor.aa)
setup_all_loops(__name__)
if __name__ == '__main__':
unittest.main(verbosity=2)
=== modified file 'utils/test/test-config.py'
--- utils/test/test-config.py 2016-10-10 21:27:19 +0000
+++ utils/test/test-config.py 2017-03-02 21:21:21 +0000
@@ -24,7 +24,7 @@
conf = ini_config.read_config('logprof.conf')
logprof_sections = ['settings', 'repository', 'qualifiers', 'required_hats', 'defaulthat', 'globs']
logprof_sections_options = ['profiledir', 'inactive_profiledir', 'logfiles', 'parser', 'ldd', 'logger', 'default_owner_prompt', 'custom_includes']
- logprof_settings_parser = '/sbin/apparmor_parser /sbin/subdomain_parser'
+ logprof_settings_parser = '../../parser/apparmor_parser'
self.assertEqual(conf.sections(), logprof_sections)
self.assertEqual(conf.options('settings'), logprof_sections_options)
=== modified file 'utils/test/test-dbus.py'
--- utils/test/test-dbus.py 2016-11-19 09:55:03 +0000
+++ utils/test/test-dbus.py 2017-02-28 23:04:24 +0000
@@ -89,6 +89,10 @@
('dbus peer=(, label = bar, name = foo ),' , exp(False, False, False, '', None , True , None, True, None, True, None, True, None, True, None, True, 'foo', False, 'bar,', False)), # XXX peerlabel includes the comma
('dbus peer=( label = bar , name = foo ),' , exp(False, False, False, '', None , True , None, True, None, True, None, True, None, True, None, True, 'foo', False, 'bar', False)),
('dbus peer=( label = "bar" name = "foo" ),' , exp(False, False, False, '', None , True , None, True, None, True, None, True, None, True, None, True, 'foo', False, 'bar', False)),
+ ('dbus path=/foo/bar bus=session,' , exp(False, False, False, '', None , True , 'session', False, '/foo/bar', False, None, True, None, True, None, True, None, True, None, True)),
+ ('dbus bus=system path=/foo/bar bus=session,' , exp(False, False, False, '', None , True , 'session', False, '/foo/bar', False, None, True, None, True, None, True, None, True, None, True)), # XXX bus= specified twice, last one wins
+ ('dbus send peer=(label="foo") bus=session,' , exp(False, False, False, '', {'send'}, False, 'session', False, None, True, None, True, None, True, None, True, None, True, 'foo', False)),
+ ('dbus bus=1 bus=2 bus=3 bus=4 bus=5 bus=6,' , exp(False, False, False, '', None , True , '6', False, None, True, None, True, None, True, None, True, None, True, None, True)), # XXX bus= specified multiple times, last one wins
]
def _run_test(self, rawrule, expected):
@@ -108,6 +112,8 @@
('dbus peer=(label=foo) path=,' , AppArmorException),
('dbus (invalid),' , AppArmorException),
('dbus peer=,' , AppArmorException),
+ ('dbus bus=session bind bus=system,', AppArmorException),
+ ('dbus bus=1 bus=2 bus=3 bus=4 bus=5 bus=6 bus=7,', AppArmorException),
]
def _run_test(self, rawrule, expected):
=== modified file 'utils/test/test-libapparmor-test_multi.py'
--- utils/test/test-libapparmor-test_multi.py 2017-01-19 15:52:38 +0000
+++ utils/test/test-libapparmor-test_multi.py 2017-03-02 21:21:53 +0000
@@ -10,7 +10,7 @@
# ------------------------------------------------------------------
import unittest
-from common_test import AATest, setup_all_loops, read_file
+from common_test import AATest, setup_all_loops, setup_aa, read_file
import os
from apparmor.common import open_file_read
@@ -267,6 +267,7 @@
TestLibapparmorTestMulti.tests = find_test_multi('../../libraries/libapparmor/testsuite/test_multi/')
TestLogToProfile.tests = find_test_multi('../../libraries/libapparmor/testsuite/test_multi/')
+setup_aa(apparmor.aa)
setup_all_loops(__name__)
if __name__ == '__main__':
unittest.main(verbosity=1) # reduced verbosity due to the big number of tests
=== modified file 'utils/test/test-mount_parse.py'
--- utils/test/test-mount_parse.py 2016-10-01 18:57:09 +0000
+++ utils/test/test-mount_parse.py 2017-03-02 21:21:53 +0000
@@ -11,7 +11,7 @@
import apparmor.aa as aa
import unittest
-from common_test import AAParseTest, setup_regex_tests
+from common_test import AAParseTest, setup_regex_tests, setup_aa
class BaseAAParseMountTest(AAParseTest):
def setUp(self):
@@ -39,6 +39,7 @@
('unmount /mnt/external,', 'unmount with mount point'),
]
+setup_aa(aa)
if __name__ == '__main__':
setup_regex_tests(AAParseMountTest)
setup_regex_tests(AAParseRemountTest)
=== modified file 'utils/test/test-parser-simple-tests.py'
--- utils/test/test-parser-simple-tests.py 2016-10-01 18:57:09 +0000
+++ utils/test/test-parser-simple-tests.py 2017-03-03 12:14:03 +0000
@@ -10,7 +10,7 @@
# ------------------------------------------------------------------
import unittest
-from common_test import AATest, setup_all_loops
+from common_test import AATest, setup_all_loops, setup_aa
import apparmor.aa as apparmor
import os
@@ -30,9 +30,6 @@
'generated_x/ambiguous-',
'generated_x/dominate-',
- # permissions before path
- 'generated_perms_leading/',
-
# 'safe' and 'unsafe' keywords
'generated_perms_safe/',
@@ -52,6 +49,7 @@
'change_profile/onx_conflict_unsafe1.sd',
'change_profile/onx_conflict_unsafe2.sd',
+ 'dbus/bad_modifier_2.sd',
'dbus/bad_regex_01.sd',
'dbus/bad_regex_02.sd',
'dbus/bad_regex_03.sd',
@@ -154,6 +152,8 @@
'vars/vars_dbus_bad_01.sd',
'vars/vars_dbus_bad_02.sd',
'vars/vars_dbus_bad_03.sd',
+ 'vars/vars_dbus_bad_04.sd',
+ 'vars/vars_dbus_bad_05.sd',
'vars/vars_dbus_bad_06.sd',
'vars/vars_dbus_bad_07.sd',
'vars/vars_file_evaluation_7.sd',
@@ -256,16 +256,75 @@
'file/ok_5.sd', # Invalid mode UX
'file/ok_2.sd', # Invalid mode RWM
'file/ok_4.sd', # Invalid mode iX
+ 'xtrans/simple_ok_pix_1.sd', # Invalid mode pIx
+ 'xtrans/simple_ok_pux_1.sd', # Invalid mode rPux
+
+ # unexpected uppercase vs. lowercase in *x rules - generated_perms_leading directory
+ 'generated_perms_leading/exact-re-Puxtarget.sd',
+ 'generated_perms_leading/dominate-ownerCuxtarget2.sd',
+ 'generated_perms_leading/ambiguous-Cux.sd',
+ 'generated_perms_leading/dominate-ownerPux.sd',
+ 'generated_perms_leading/exact-re-ownerPux.sd',
+ 'generated_perms_leading/overlap-ownerCuxtarget.sd',
+ 'generated_perms_leading/exact-re-ownerCuxtarget.sd',
+ 'generated_perms_leading/dominate-Puxtarget2.sd',
+ 'generated_perms_leading/dominate-ownerCuxtarget.sd',
+ 'generated_perms_leading/dominate-ownerPuxtarget.sd',
+ 'generated_perms_leading/ambiguous-Pux.sd',
+ 'generated_perms_leading/ambiguous-Cuxtarget2.sd',
+ 'generated_perms_leading/exact-Puxtarget2.sd',
+ 'generated_perms_leading/ambiguous-ownerCux.sd',
+ 'generated_perms_leading/exact-ownerPux.sd',
+ 'generated_perms_leading/ambiguous-ownerPuxtarget.sd',
+ 'generated_perms_leading/exact-re-ownerPuxtarget.sd',
+ 'generated_perms_leading/exact-re-Cuxtarget.sd',
+ 'generated_perms_leading/exact-re-Puxtarget2.sd',
+ 'generated_perms_leading/dominate-Cux.sd',
+ 'generated_perms_leading/exact-re-ownerCuxtarget2.sd',
+ 'generated_perms_leading/ambiguous-ownerCuxtarget.sd',
+ 'generated_perms_leading/exact-re-Cuxtarget2.sd',
+ 'generated_perms_leading/ambiguous-Puxtarget.sd',
+ 'generated_perms_leading/overlap-Puxtarget.sd',
+ 'generated_perms_leading/ambiguous-Puxtarget2.sd',
+ 'generated_perms_leading/overlap-Puxtarget2.sd',
+ 'generated_perms_leading/exact-Puxtarget.sd',
+ 'generated_perms_leading/overlap-ownerPuxtarget.sd',
+ 'generated_perms_leading/exact-ownerCuxtarget.sd',
+ 'generated_perms_leading/exact-re-ownerCux.sd',
+ 'generated_perms_leading/exact-ownerPuxtarget2.sd',
+ 'generated_perms_leading/exact-ownerCux.sd',
+ 'generated_perms_leading/overlap-Cuxtarget2.sd',
+ 'generated_perms_leading/ambiguous-Cuxtarget.sd',
+ 'generated_perms_leading/ambiguous-ownerPuxtarget2.sd',
+ 'generated_perms_leading/dominate-ownerCux.sd',
+ 'generated_perms_leading/exact-Pux.sd',
+ 'generated_perms_leading/exact-Cuxtarget.sd',
+ 'generated_perms_leading/overlap-ownerCuxtarget2.sd',
+ 'generated_perms_leading/overlap-Pux.sd',
+ 'generated_perms_leading/overlap-ownerPux.sd',
+ 'generated_perms_leading/ambiguous-ownerCuxtarget2.sd',
+ 'generated_perms_leading/exact-re-Cux.sd',
+ 'generated_perms_leading/exact-re-Pux.sd',
+ 'generated_perms_leading/overlap-Cuxtarget.sd',
+ 'generated_perms_leading/exact-re-ownerPuxtarget2.sd',
+ 'generated_perms_leading/exact-Cuxtarget2.sd',
+ 'generated_perms_leading/exact-Cux.sd',
+ 'generated_perms_leading/overlap-Cux.sd',
+ 'generated_perms_leading/overlap-ownerCux.sd',
+ 'generated_perms_leading/exact-ownerPuxtarget.sd',
+ 'generated_perms_leading/dominate-Pux.sd',
+ 'generated_perms_leading/exact-ownerCuxtarget2.sd',
+ 'generated_perms_leading/dominate-Puxtarget.sd',
+ 'generated_perms_leading/ambiguous-ownerPux.sd',
+ 'generated_perms_leading/overlap-ownerPuxtarget2.sd',
+ 'generated_perms_leading/dominate-Cuxtarget2.sd',
+ 'generated_perms_leading/dominate-Cuxtarget.sd',
+ 'generated_perms_leading/dominate-ownerPuxtarget2.sd',
+
+ # escaping with \
'file/ok_embedded_spaces_4.sd', # \-escaped space
'file/file/ok_embedded_spaces_4.sd', # \-escaped space
'file/ok_quoted_4.sd', # quoted string including \"
- 'xtrans/simple_ok_pix_1.sd', # Invalid mode pIx
- 'xtrans/simple_ok_pux_1.sd', # Invalid mode rPux
-
- # dbus regex mismatch
- 'vars/vars_dbus_4.sd',
- 'vars/vars_dbus_9.sd',
- 'vars/vars_dbus_2.sd',
# misc
'vars/vars_dbus_8.sd', # Path doesn't start with / or variable: {/@{TLDS}/foo,/com/@{DOMAINS}}
@@ -399,6 +458,7 @@
print('Running %s parser simple_tests...' % len(TestParseParserTests.tests))
+setup_aa(apparmor)
find_and_setup_test_profiles('../../parser/tst/simple_tests/')
setup_all_loops(__name__)
=== modified file 'utils/test/test-pivot_root_parse.py'
--- utils/test/test-pivot_root_parse.py 2016-10-01 18:57:09 +0000
+++ utils/test/test-pivot_root_parse.py 2017-03-02 21:21:53 +0000
@@ -11,7 +11,7 @@
import apparmor.aa as aa
import unittest
-from common_test import AAParseTest, setup_regex_tests
+from common_test import AAParseTest, setup_regex_tests, setup_aa
class AAParsePivotRootTest(AAParseTest):
def setUp(self):
@@ -24,6 +24,7 @@
('pivot_root /old /new -> /usr/bin/child,', 'pivot_root child rule'),
]
+setup_aa(aa)
if __name__ == '__main__':
setup_regex_tests(AAParsePivotRootTest)
unittest.main(verbosity=2)
=== modified file 'utils/test/test-regex_matches.py'
--- utils/test/test-regex_matches.py 2016-10-01 18:57:09 +0000
+++ utils/test/test-regex_matches.py 2017-03-02 21:21:53 +0000
@@ -11,7 +11,7 @@
import apparmor.aa as aa
import unittest
-from common_test import AATest, setup_all_loops
+from common_test import AATest, setup_all_loops, setup_aa
from apparmor.common import AppArmorBug, AppArmorException
from apparmor.regex import ( strip_parenthesis, strip_quotes, parse_profile_start_line, re_match_include,
@@ -502,6 +502,7 @@
+setup_aa(aa)
setup_all_loops(__name__)
if __name__ == '__main__':
# these two are not converted to a tests[] loop yet
=== modified file 'utils/test/test-unix_parse.py'
--- utils/test/test-unix_parse.py 2016-10-01 18:57:09 +0000
+++ utils/test/test-unix_parse.py 2017-03-02 21:21:53 +0000
@@ -11,7 +11,7 @@
import apparmor.aa as aa
import unittest
-from common_test import AAParseTest, setup_regex_tests
+from common_test import AAParseTest, setup_regex_tests, setup_aa
class AAParseUnixTest(AAParseTest):
@@ -34,6 +34,7 @@
'complex unix rule'),
]
+setup_aa(aa)
if __name__ == '__main__':
setup_regex_tests(AAParseUnixTest)
unittest.main(verbosity=2)
vim:ft=diff