Change parse_profile_data() to internally use merged profile names
(`foo//bar`) instead of separate profile and hat, and only split it up
again to the [profile][hat] layout at the very end with
merged_to_split().
A nice side effect is that we get rid of a hasher() usage.
parse_profile_data() also gets changed to use `hat = None` (instead of
`hat = profile`) if not inside a child profile. As a result,
parse_profile_start() and one of its tests need a small change.
Besides that small change, calling code should not see a difference, and
the tests also stay working.
Also adjust the calling code to use get_header() instead of
write_header().
Finally, move the tests to test-profile-storage.py and do a few
adjustments needed by the change. Part of these adjustments is to hand
over empty params with the correct type instead of just "None".
in_preamble keeps track of the current parsing position.
It's True while parsing the preamble of a profile file, and when loading
an include file that is included in the preamble (typically tunables/*).
While inside a profile or parsing abstractions/*, it is False.
This commit only hands the information around and keeps in_preamble
updated, but it doesn't really get used yet.
Also adjust the tests to hand over the additional parameter to
parse_profile_data().
Since loadincludes() now only loads a specified list of subdirectories,
we no longer need a directory blacklist.
The only possibly remaining part are .git subdirectories (for example
tunables/.git or abstractions/.git). Since it's very unlikely that
someone would have only a subdirectory of /etc/apparmor.d/ in git, drop
that check.
in_contained_hat is needed to know if we are already in a profile or
not. (Simply checking if we are in a hat doesn't work, because something
like "profile foo//bar" will set profile and hat at once, and later
(wrongfully) expect another "}".
However, the way how this variable was set became too complicated.
To simplify the code, set in_contained_hat directly in
parse_profile_data() RE_PROFILE_START instead of returning it via
parse_profile_start() and parse_profile_start_to_storage()
Since this change removes a return value from two functions, also adjust
the tests accordingly.
parse_profile_start_to_storage() converts the result of
parse_profile_start() into a ProfileStorage object.
No functional change, but parse_profile_data() becomes more readable.
Also extend tests to cover parse_profile_start_to_storage().
This removes the need to remove profile_dir from include paths at
various places.
A side effect is that aa-logprof / match_includes() now propose more
include rules, for example matching local/ files.
Another side effect is that proposals for include rules
(match_includes() again) now come with the full path.
Both side effects will be fixed in the next commits.
... and write them (only) from 'inc_ie' (IncludeRuleset), which can
handle both "include" and "include if exists" rules.
This duplicates storage of include rules because 'include' is still used
and needed at various places that work on/with the include rules.
With this, we get removal of duplicate include lines insinde a profile
in aa-cleanprof "for free" - extend cleanprof_test.in to confirm this.
Instead of checking filelist[file]['profiles'] for duplicate hats, check
profile_data[profile][hat].
With this, the duplicate hat check is done in the same way as the check
for duplicate profiles and child profiles.
Also add tests for duplicate child profiles and duplicate hats.
Since !345 the set of permissions that are granted (get_file_perms_2)
or suggested (propose_file_rules) has changed. These new sets are
expected due to the changes brought by this MR, so let's adjust
the test suite accordingly.
... instead of overwriting them with the flags of the main profile.
This fixes a longstanding issue with aa-complain, aa-enforce and
aa-audit which broke the flags of child profiles and hats if they
differed from the main profile.
It also fixes several issues documented in the tests (which obviously
need adjustment to match the fixed behaviour).
Also change the "no profile found" cases to AppArmorException - errors
in a profile are not worth triggering AppArmorBug ;-)
All callers call change_profile_flags(), so it makes sense to test this
function instead of set_profile_flags().
Besides that, set_profile_flags() will be merged into
change_profile_flags() in the next commit ;-)
Note that this commit adds some '# XXX' notes to the tests. These will
be addressed in later commits.
parse_profile_start(): Error out on nested child profiles
See merge request apparmor/apparmor!136
Acked-by: John Johansen <john.johansen@canonical.com> for 2.10..master
The tools can't handle nested child profiles yet. Instead of failing
in funny[tm] ways (parse_profile_start() only returned the first two
segments of the profile name) better error out with a clear message.
ProfileStorage() stores the content of a profile, so it makes sense to
also have the functions to write those rules (including helper functions
used by these functions) in the same file.
Note that I only moved the functions for rule types that are not handled
by *Ruleset classes.
The functions for writing rules stored in a *Ruleset class will
hopefully be superfluous sooner or later (probably later because
serialize_parse_profile_start() depends on them, and rewriting it won't
be easy)
Also move the test for var_transform() to test-profile-storage.py.
This excludes the /etc/apparmor.d/cache.d/ directory from aa-logprof
parsing because parsing the binary cache, well, takes a while :-/
Reported on the opensuse-factory mailinglist by Frank Krüger and
confirmed by others.
For now we only allow quoted absolute paths without spaces in the name
due to:
- 1738877: include rules don't handle files with spaces in the name
- 1738879: include rules don't handle absolute paths without quotes in
some versions of parser
- 1738880: include rules don't handle relative paths in some versions of
the parser
- move the code of set_options_audit_mode() to a new function
set_options_mode() and make set_options_audit_mode() a wrapper for it.
- add set_options_owner_mode() as another wrapper for set_options_mode()
and add code to switch the owner flag to set_options_mode()
- add tests for set_options_owner_mode()
get_file_perms() and propose_file_rules() happily collect all file
permissions. This could lead to proposing 'wa' permissions in
aa-logprof, which then errored out because of conflicting permissions.
This patch adds a check to both functions that removes 'a' if 'w' is
present, and extends the tests to check this.
Acked-by: Seth Arnold <seth.arnold@canonical.com> for trunk and 2.11.
Note: Both functions (including this bug) were introduced together with
FileRule, so older releases are not affected.
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>
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>
ldd exits with $? == 1 if a file is 'not a dynamic executable'.
This is correct behaviour of ldd, so we should handle it instead of
raising an exception ;-)
Also extend fake_ldd and add a test to test-aa.py to cover this.
Note that 2.10 and 2.9 don't have tests for get_reqs() nor fake_ldd,
so those branches will only get the aa.py changes.
Acked-by: John Johansen <john.johansen@canonical.com> for trunk, 2.10 and 2.9.
As discussed a while ago, switch the utils (including their tests) to
use python3 by default. While on it, drop usage of "env" to always get
the system python3 instead of a random one that happens to live
somewhere in $PATH.
In practise, this patch doesn't change much - AFAIK openSUSE, Debian and
Ubuntu already patch aa-* to use python3.
Also add a note to README to officially deprecate Python 2.x.
(I won't break Python 2.x support intentionally - unless some future
change gives me a very good reason to finally drop Python 2.x support.)
Acked-by: Seth Arnold <seth.arnold@canonical.com>
(since 2016-08-23, but the commit had to wait for the FileRule series
because it touches test-file.py)
Add set_options_audit_mode() to switch the audit mode in all options
offered by aa-logprof and aa-mergeprof, not only the "original" rule
(in aa-logprof, this means the non-globbed rule_obj).
As usual, add some tests to ensure the function works as expected.
Acked-by: Steve Beattie <steve@nxnw.org>
aa.py:
- add propose_file_rules() - will propose matching paths from existing
rules in the profile or one of the includes
- save user_globs if user selects '(N)ew' (will be re-used when
proposing rules)
- change user_globs to a dict so that it can carry the human-readable
path and an AARE object for it
- change order_globs() to ensure the original path (given as parameter)
is always the last item in the resulting list
- add a ruletype switch to ask_the_questions() so that it uses
propose_file_rules() for file events (I don't like this
ruletype-specific solution too much, but everything else would make
things even more complicated)
Also keep aa-mergeprof ask_the_questions() in sync with aa.py.
In FileRule, add original_perms (might be set by propose_file_rules())
Finally, add some tests to ensure propose_file_rules() does what it promises.
Acked-by: Steve Beattie <steve@nxnw.org>
get_file_perms() collects the existing permissions for a file from
various rules (exact matches, wildcards) in the main profile and the
included abstractions.
It will be used to get displaying the current permissions back, and
also to propose rules with merged permissions (next patch).
Also add some tests to make sure it does what it promises ;-)
Acked-by: Steve Beattie <steve@nxnw.org>
This patch changes handle_children() (which asks about exec events) and
ask_the_questions() (which asks everything else) to FileRule. This
solves the "brain split" introduced by the previous patch.
This means aa-logprof and aa-genprof ask useful questions again, and
store the answers at the right place.
In detail, this means (with '-' line number from the diff)
- (391) handle_binfmt(): use FileRule. Also avoid breakage if glob_common()
returns an empty result.
- (484) profile_storage(): drop profile['allow']['path'] and
profile['deny']['path']
- (510) create_new_profile(): switch to FileRule
- (1190..1432) lots of changes in handle_children():
- drop escaping (done in FileRule)
- don't add events with 'x' perms to prelog
- use is_known_rule() instead of profile_known_exec()
- replace several regexes for the selected CMD_* with more readable
'in' clauses. While on it, drop unused parts of the regex.
- use plain 'ix', 'px' (as str) instead of str_to_mode() format
- call handle_binfmt() for the interpreter in ix, Pix and Cix rules
- (1652) ask_the_questions(): disable the old file-specific code
(not dropped because some features aren't ported to FileRule yet)
- (2336) collapse_log():
- convert file log events to FileRule (and add some workarounds and
TODOs for logparser.py behaviour that needs to change)
- disable the old file-specific code (not dropped because merging of
existing permissions isn't ported to FileRule yet)
- (2403) drop now unused validate_profile_mode() and the regexes it used
- (3374) drop now unused profile_known_exec()
Test changes:
- adjust fake_ldd to handle /bin/bash
- change test-aa.py AaTest_create_new_profile to expect FileRule instead
of a path hasher. Also copy the profiles to the tempdir and load the
abstractions that are needed by the test.
(These tests get skipped on py2 because changing
apparmor.aa.cfg['settings']['ldd'] doesn't work for some unknown reason)
Important: Some nice-to-have features are not yet implemented for
FileRule:
- globbing
- (N)ew (allowing the user to enter a custom path)
- displaying and merging of permissions already existing in the profile
This means: aa-logprof works, but it's not as user-friendly as before.
The next patches will fix that ;-)
Also note that pyflakes will fail for ask_the_questions_OLD_FILE_CODE()
because of undefined symbols (aamode, profile, hat). This will be fixed
when the old code gets dropped in one of the later patches.
Acked-by: Steve Beattie <steve@nxnw.org>
Bug: https://launchpad.net/bugs/1569316
For reasons that aren't entirely clear, the action to set
apparmor.aa.cfg['settings']['ldd'] to './fake_ldd' does not actually
work on python2.7, get_reqs() tries to use /usr/bin/ldd anyway (printing
out the contents of apparmor.aa.cfg['settings']['ldd'] after the set
operation shows it to still contain '/usr/bin/ldd' o.O). Therefore, skip
these two tests when running under python2.7.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Christian Boltz <apparmor@cboltz.de>
Bug: https://launchpad.net/bugs/1522938
If the program specified as get_output param isn't executable or doesn't
exist at all, get_output() returns with ret = -1.
Raising an exception looks like a better option, especially because
other possible exec failures already raise an exception ("Unable to
fork").
Note: get_output is only used by get_reqs() which also does the
os.access() check for x permissions (and raises an exception), so in
practise raising an exception in get_output() doesn't change anything.
This change also allows to rewrite and simplify get_output() quite a bit.
Another minor change (and fix) is in the removal of the last line. The
old code removed the last line if output contained at least two items.
This had two not-so-nice effects:
- an empty output resulted in [''] instead of []
- if a command didn't add a \n on the last line, this line was deleted
nevertheless
The patch changes that to always remove the last line if it is empty,
which fixes both issues mentioned above.
Also add a test to ensure the exception is really raised, and adjust the
test that expects an empty stdout.
Acked-by: Kshitij Gupta <kgupta8592@gmail.com>
To make these tests independent from the underlaying system, add a
fake_ldd script that provides hardcoded ldd output for the "known"
executables and libraries.
To avoid interferences with the real system (especially symlinks), all
paths in fake_ldd have '/AATest' prepended.
Acked-by: Kshitij Gupta <kgupta8592@gmail.com>
On Debian and Ubuntu it's possible to have multiple ruby interpreters
installed, and the default to use is handled by the ruby-defaults
package, which includes a symlink from /usr/bin/ruby to the versioned
ruby interpreter.
This patch makes aa.py:get_interpreter_and_abstraction() take that into
account by using a regex to match possible versions of ruby. Testcases
are included. (I noticed this lack of support because on Ubuntu the ruby
test was failing because get_interpreter_and_abstraction() would get the
complete path, which on my 16.04 laptop would get /usr/bin/ruby2.2.)
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Seth Arnold <seth.arnold@canonical.com>