Also add loop support to test-aa.py.
BTW: In case you wonder - the need to replace unittest.TestCase with
AATest is intentional. It might look annoying, but it makes sure that
a test-*.py file doesn't contain a test class where tests = [...] is
ignored because it's still unittest.TestCase.
(Technically, setup_all_tests() will error out if a test class doesn't
contain tests = [...] - either explicit or via its parent AATest.)
Acked-by: Steve Beattie <steve@nxnw.org>
Add various tests for set_profile_flags, and document various
interesting[tm] things I discovered while writing the tests (see
the inline comments for details).
Also adds a read_file() function to common_test.py.
The most interesting[tm] thing I found is:
regex_hat_flag = re.compile('^([a-z]*)\s+([A-Z]*)\s*(#.*)?$')
which matches various unexpected things - but not a hat :-/
(see mailinglist for all funny details)
Acked-by: Steve Beattie <steve@nxnw.org>
Convert serialize_parse_profile_start() to use
parse_profile_start_line(), and adjust a test to expect an AppArmorBug
instead of an AttributeError exception.
Also add two tests (they succeed with the old and the new code).
Note that these tests document interesting[tm] behaviour - I tend to
think that those cases should raise an exception, but I'm not sure about
this because serialize_profile_from_old_profile() is a good example for
interesting[tm] code :-/
I couldn't come up with a real-world test profile that would hit those
cases without erroring out aa-logprof earlier - maybe the (more
sane-looking) parse_profiles() / serialize_parse_profile_start()
protects us from hitting this interesting[tm] behaviour.
Acked-by: Steve Beattie <steve@nxnw.org>
The commit message for r2976 says:
[...]
The patch also adds test-example.py, which is
- a demo of the code added to common_test.py
- a template file that we can copy for future test-*.py
Acked-by: Steve Beattie <steve@nxnw.org>
but I forgot to add test-example.py to bzr, which I hereby do.
The previous patch slightly changed the behaviour of parse_profile_start()
and get_profile_flags() - they raise AppArmorBug instead of
AppArmorException when specifying a line that is not the start of a
profile and therefore doesn't match RE_PROFILE_START_2.
This patch updates test-aa.py to expect the correct exceptions, and adds
another test with quoted profile name to ensure that stripping the
quotes works as expected.
Acked-by: Steve Beattie <steve@nxnw.org>
Add the parse_profile_start_line() function to regex.py, which is a
wrapper for RE_PROFILE_START_2 and returns an array with named matches.
Also change some places in aa.py from using RE_PROFILE_START to the
parse_profile_start_line() function.
Notes:
- until everything is migrated to the new function, I'll keep the old
RE_PROFILE_START unchanged - that's the reason to add the new regex
as RE_PROFILE_START_2
- the patch changes only aa.py sections that are covered by tests already
(which means some users of RE_PROFILE_START are remaining)
- parse_profile_start_line() merges 'profile' and 'attachment' into
'profile' (aka the old, broken behaviour) until aa.py can handle the
attachment properly. The alternative would be to ignore 'attachment',
which would be worse.
Acked-by: Steve Beattie <steve@nxnw.org>
Add better support for looping over a tests[] array to common_test.py:
- class AATest - a base class we can use for all tests, and that will
probably get more features in the future (for example tempdir
handling)
- setup_all_tests() - a function that iterates over all classes in the
given file and calls setup_test_loops() for each of them
- setup_tests_loop() - a function that creates tests based on tests[]
in the given class. Those tests call the class' _run_test() method for
each test specified in tests[] (inspired by setup_regex_tests() ;-)
This means we can get rid of the manually maintained tests list in
test-regex_matches.py and just need to call setup_all_tests() once in
each file.
The patch also adds test-example.py, which is
- a demo of the code added to common_test.py
- a template file that we can copy for future test-*.py
Acked-by: Steve Beattie <steve@nxnw.org>
serialize_profile_from_old_profile() in aa.py, as a preparation to add
tests and then switch to the upcoming RE_PROFILE_START wrapper function.
Besides moving the code, I replaced write_prof_data[profile][hat]['profile']
and write_prof_data[profile][hat]['external'] with function parameters
to avoid that I have to pass around the full write_prof_data.
Note: The "lineno" parameter is technically superfluous - I kept it to
have the parameters as close to parse_profile_start() as possible and
hope that I can merge those functions later (when we have test coverage).
Acked-by: Steve Beattie <steve@nxnw.org> for trunk and 2.9.
and change the code to use them.
Also add a comment to act() that it's only used by aa-cleanprof.
Note: The new functions add the --base parameter to the apparmor_parser
calls, which also means the disable directory inside the given profile
dir (and not always /etc/apparmor.d/disable) is now honored.
Acked-by: Steve Beattie <steve@nxnw.org> for trunk and 2.9.
logparser.py / add_event_to_tree() has 5 places to handle 'path' events.
This patch merges most if conditions to reduce that to 2 places.
It also makes the matching a bit more strict - instead of using 'in',
'xattr' has to be an exact match and 'file_' is matched with startswith().
Also, 'getattr' is added to the list of file events.
Acked-by: Steve Beattie <steve@nxnw.org>
---------- trunk only, unclear for 2.9 --------------
Without it, aa-disable
- didn't error out when hitting a broken profile directory
- didn't find a profile if it doesn't use the default naming scheme
(for example /bin/true profile hiding in bin.false)
Acked-by: Steve Beattie <steve@nxnw.org> for trunk and 2.9
aa-status was crashing when parsing through /proc/mounts looking to see
if and where the securityfs synthetic file system is mounted if there
was a mount point that contained characters outside of the charset in
use in the environment of aa-status. This patch fixes the issue by
converting the read of /proc/mounts into a binary read and then uses
decode on the elements.
Patch by Alain BENEDETTI.
Acked-by: Steve Beattie <steve@nxnw.org>
As a follow-up to the logparser.py change that converts disconnected
path events to an error, add a testcase to test-logparser.py.
Acked-by: Steve Beattie <steve@nxnw.org> for both trunk and 2.9.
The upcoming function parse_profile_start() (which is a wrapper around
the updated RE_PROFILE_START, and will live in regex.py) needs
strip_profile(), but importing it from aa.py fails with an import loop.
Therefore this patch moves strip_quotes() from aa.py to regex.py and
re-imports it into aa.py.
As a bonus, the patch also adds some tests for strip_quotes() ;-)
Also add TestStripQuotes to the test_suite list because it won't run
otherwise.
Acked-by: Steve Beattie <steve@nxnw.org> for both trunk and 2.9
Move the code for parsing the profile start ("/foo {") from aa.py
parse_profile_data() to a separate function parse_profile_start().
Most of the changes are just moving around code, with some small
exceptions:
- instead of handing over profile_data to parse_profile_start() to
modify it, it sets two variables (pps_set_profile and
pps_set_hat_external) as part of its return value, which are then
used in parse_profile_data() to set the flags in profile_data.
- existing_profiles[profile] = file is executed later, which means
it used the strip_quotes() version of profile now
- whitespace / tab level changes
The patch also adds some tests for the parse_profile_start() function.
Acked-by: Steve Beattie <steve@nxnw.org>
Also adds a check to get_profile_flags() to catch an invalid syntax:
/foo ( ) {
was accepted by get_profile_flags, while
/foo () {
failed.
When testing with the parser, both result in a syntax error, therefore
the patch makes sure it also fails in get_profile_flags().
Acked-by: Steve Beattie <steve@nxnw.org>
This means that aa-logprof will ignore the event instead of crashing with
AppArmorException: 'Unexpected rank input: var/run/nscd/passwd'
Note that I made the check as specific as possible to be sure it doesn't
hide other events.
References: https://bugzilla.opensuse.org/show_bug.cgi?id=918787
Acked-by: Steve Beattie <steve@nxnw.org>
Also update test-capability.py - it contains a test that needs
'error_code': 0,
added to avoid a failure.
Patch by: Steve Beattie <steve@nxnw.org>
Acked-by: Christian Boltz <apparmor@cboltz.de>
Remove the check if the disable directory exists. If it's really
missing, it will be auto-created by create_symlink(), so we
automagically fix things instead of annoying the user with an
error message ;-)
Acked-by: Steve Beattie <steve@nxnw.org> for both trunk and 2.9.
Make sure most tools (for example aa-complain) don't error out if
no logfile can be found. (For obvious reasons, aa-logprof and
aa-genprof will still require a logfile ;-)
This is done by moving code from the global area in aa.py to the new
function set_logfile(), which is called by aa-logprof and aa-genprof.
While on it,
- rename apparmor.filename to apparmor.logfile
- move the error handling for user-specified logfile from aa-genprof
and aa-logprof to aa.py set_logfile()
Note: I'd have prefered to hand over the logfile as parameter to
do_logprof_pass(), but that would break last_audit_entry_time() in
aa-genprof which requires the log filename before do_logprof_pass()
is called.
References: https://bugs.launchpad.net/apparmor/+bug/1423702
Acked-by: Seth Arnold <seth.arnold@canonical.com>
libapparmor _aa_is_blacklisted() - some extensions were missing in the
python code.
Also make the code more readable and add some testcases.
Notes:
- the original code additionally ignored *.swp. I didn't include that -
*.swp looks like vim swap files which are also dot files
- the python code ignores README files, but the C code doesn't
(do we need to add README in the C code?)
Acked-by: Kshitij Gupta <kgupta8592@gmail.com> for 2.9 and trunk
Acked-by: Steve Beattie <steve@nxnw.org>
string or if a mode_char is not in MODE_HASH.
Also update the testcase for "asdf42" (which raises AppArmorBug now)
and add a test that simulates MODE_HASH and MODE_MAP_SET getting out
of sync (tests the second part of the if condition).
Acked-by: Steve Beattie <steve@nxnw.org>
Since the Makefile cleanup, the _clean target is only used to delete
manpages etc. generated from *.pod files.
This patch renames the _clean target to pod_clean to make it obvious
what it does.
Acked-by: John Johansen <john.johansen@canonical.com>
- drop the symlink magic of the common/ directory, and just include
files directly from there.
- update comments indicating required steps to take when including
common/Make.rules
- drop make clean steps that refer to no longer generated tarballs,
specfiles, and symlinks to the common directory/Make.rules.
- don't silence clean steps if VERBOSE is set
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Christian "Ghostbuster" Boltz <apparmor@cboltz.de>
Split is_covered() in capability.py into
- is_covered_localparts() for rule-specific code
- is_covered() for common code - located in __init__.py
The object type comparison now uses type(self) and a slightly different
error message to make it usable everywhere.
Also rename rule_obj to other_rule which is more self-explaining
(inspired by the parameter name in the is_covered() dummy in __init__.py).
v2:
- remove check_allow_deny and check_audit parameters from
is_covered_localvars()
Acked-by: Steve Beattie <steve@nxnw.org>
If one of the testcases fail, this goes unnoticed in "make coverage".
This patch changes the Makefile so that test failures let
"make coverage" fail.
You can use make COVERAGE_IGNORE_FAILURES=true coverage to build
coverage data even if some tests fail.
Signed-off-by: Steve Beattie <steve@nxnw.org>
(which was most probably meant as an Acked-by)
Also Acked-by: <timeout> ;-)
For reasons that are unclear, python's setuptools doesn't install
recursively from a directory, meaning that on make install, the new
Rules/Ruleset classes were not being installed. This patch causes
the rule subdirectory to be included.
Bug: https://bugs.launchpad.net/bugs/1407437
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Tyler Hicks <tyhicks@canonical.com>
adds some tests for severity.py and improves the test coverage to
nearly 100% (only 3 partial left).
Added tests and details (all in SeverityVarsTest):
- move writing the tunables file from setUp() into _init_tunables() for
more flexibility (allows to specify other file content)
- test adding to a variable (+=)
- test #include
- make sure double definition of a variable fails
- make sure redefinition of non-existing variable fails
BTW: even the comment added to VARIABLE_DEFINITIONS contributes to
the coverage ;-)
severity.py passes all added tests, however I should note that including
a non-existing file is silently ignored.
Acked-by: Kshitij Gupta <kgupta8592@gmail.com>
This patch hides raw_rule within the BaseRule class by making parse() be
a class method for all the rule types, implemented via a rule-specific
abstract method _parse() that returns a parsed Rule object.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Christian Boltz <apparmor@cboltz.de>
This patch integrated the new capability rule class into aa.py and
cleanprof.py.
Patch changes:
v6:
- fix logic around same_file in cleanprofile.py that was causing
capabilities to be deleted when they weren't covered by an
abstraction.
v5:
- merge my changes into Christian's original patches
- use CapabilityRule.parse() for parsing raw capability rules and
getting a CapabilityRule instance back
- cope with move of parse_modifiers back into rule/__init__.py.
Originally-by: Christian Boltz <apparmor@cboltz.de>
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Christian Boltz <apparmor@cboltz.de>
Patch changes:
v5:
- merge my changes into Christian's original patches
- update to use CapabilityRule.parse() as the entry point for
parsing raw rules and getting a CapabilityRule instance in
return.
Originally-by: Christian Boltz <apparmor@cboltz.de>
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Christian Boltz <apparmor@cboltz.de>
This patch adds four classes - two "base" classes and two specific for
capabilities:
utils/apparmor/rule/__init__.py:
class base_rule(object):
Base class to handle and store a single rule
class base_rules(object):
Base class to handle and store a collection of rules
utils/apparmor/rule/capability.py:
class capability_rule(base_rule):
Class to handle and store a single capability rule
class capability_rules(base_rules):
Class to handle and store a collection of capability rules
Changes:
v5:
- flattened my changes into Christian's patches
- pull parse_modifiers into rule/__init__.py
- pull parse_capability into rule/capability.py
- make CapabiltyRule.parse() be the class/static method for parsing
raw capability rules.
- parse_capability: renamed inlinecomment and rawrule to comment
and raw_rule to be consistent with CapabilityRule fields.
Originally-by: Christian Boltz <apparmor@cboltz.de>
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Christian Boltz <apparmor@cboltz.de>