Commit graph

31 commits

Author SHA1 Message Date
Steve Beattie
ec9292bd5e utils: handle versioned ruby interpreters
Merge from trunk revision 3353

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>
2016-01-25 23:05:47 -08:00
Christian Boltz
6e846245ab Adjust test-aa.py for python2
This means:
- expect unicode (instead of str) when reading from a file in py2
- convert keys() result to a set to avoid test failures because of
  dict_keys type

After this change, all tests work for both py2 and py3.


Acked-by: Tyler Hicks <tyhicks@canonical.com> for trunk and 2.10.
2015-12-17 23:45:33 +01:00
Christian Boltz
d5824674d1 Several fixes for variable handling
Parsing variables was broken in several ways:
- empty quotes (representing an intentionally empty value) were lost,
  causing parser failures
- items consisting of only one letter were lost due to a bug in RE_VARS
- RE_VARS didn't start with ^, which means leading garbage (= syntax
  errors) was ignored
- trailing garbage was also ignored

This patch fixes those issues in separate_vars() and changes
var_transform() to write out empty quotes (instead of nothing) for empty
values.

Also add some tests for separate_vars() with empty quotes and adjust
several tests with invalid syntax to expect an AppArmorException.

var_transform() gets some tests added.

Finally, remove 3 testcases from the "fails to raise an exception" list
in test-parser-simple-tests.py.



Acked-by: John Johansen <john.johansen@canonical.com> for trunk and 2.9
(which also implies 2.10)


Note: 2.9 doesn't have test-parser-simple-tests.py, therefore it won't
get that part of the patch.
2015-12-12 13:01:19 +01:00
Christian Boltz
bdd8884ab4 Fix handling of interpreters with parameters
If a script contains a hashbang like
    #! /usr/bin/perl -w
aa-autodep created a profile entry like
    "/usr/bin/perl -w" ix,
which is obviously incorrect.

This patch fixes this (by using only the first part of the hashbang line)
and also adds some tests for it.

References: https://bugs.launchpad.net/apparmor/+bug/1505775


Acked-by: Kshitij Gupta <kgupta8592@gmail.com>

Bug: https://launchpad.net/bugs/1393979
2015-10-20 23:18:43 +02:00
Christian Boltz
d5e9a7ec70 merge script handling into get_interpreter_and_abstraction()
Both create_new_profile() and handle_children() check if the given exec
target is a script and add permissions for the interpreter and a
matching abstraction.

This patch merges that into the get_interpreter_and_abstraction()
function and changes create_new_profile() and handle_children() to use
this function.

A nice side effect is that handle_children() now knows more abstractions
(its original list was incomplete).
The behaviour of create_new_profile() doesn't change.

Also add tests for get_interpreter_and_abstraction() to make sure it
does what we expect.


Acked-by: Kshitij Gupta <kgupta8592@gmail.com>

Bug: https://launchpad.net/bugs/1505775
2015-10-20 23:16:41 +02:00
Christian Boltz
19d3b63db3 Add tests for create_new_profile()
These tests ensure that create_new_profile() sets the expected basic
permissions for scripts and non-script files.


Acked-by: John Johansen <john.johansen@canonical.com>
2015-10-20 23:14:42 +02:00
Christian Boltz
ada85bf219 Add more set_profile_flags() tests
The existing tests didn't test removing all flags.


Acked-by: Steve Beattie <steve@nxnw.org>
2015-06-26 23:21:29 +02:00
Christian Boltz
8d348b328b let parse_profile_data() check for in-file duplicate profiles
Add a check to parse_profile_data() to detect if a file contains two
profiles with the same name.

Note: Two profiles with the same name, but in different files, won't be
detected by this check.

Also add basic tests to ensure that a valid profile gets parsed, and two
profiles with the same name inside the same file raise an exception.

(Sidenote: these simple tests improve aa.py coverage from 9% to 12%,
which also confirms the function is too long ;-)


Acked-by: Steve Beattie <steve@nxnw.org>
2015-05-29 13:00:32 +02:00
Christian Boltz
5fa5125fd4 Add tempdir and tempfile handling to AATest
Add writeTmpfile() to AATest to write a file into the tmpdir. If no
tmpdir exists yet, automatically create one.

createTmpdir() is a separate function so that it's possible to manually
create the tmpdir (for example, if a test needs an empty tmpdir).

Also add a tearDown() function to delete the tmpdir again. This function
calls self.AATeardown() to avoid the need for super() in child classes.

Finally, simplify AaTestWithTempdir in test-aa.py to use createTmpdir()
and add an example for AATeardown() to test-example.py.



Acked-by: Steve Beattie <steve@nxnw.org>
2015-05-29 12:55:38 +02:00
Christian Boltz
f26b035e90 Let set_profile_flags() change the flags for all hats
It did this in the old 2.8 code, but didn't in 2.9.x (first there was a
broken hat regex, then I commented out the hat handling to avoid
breakage caused by the broken regex).

This patch makes sure the hat flags get set when setting the flags for
the main profile.

Also change RE_PROFILE_HAT_DEF to use more named matches
(leadingwhitespace and hat_keyword). Luckily all code that uses the
regex uses named matches already, which means adding another (...) pair
doesn't hurt.

Finally adjust the tests:
- change _test_set_flags to accept another optional parameter
  expected_more_rules (used to specify the expected hat definition)
- add tests for hats (with '^foobar' and 'hat foobar' syntax)
- add tests for child profiles, one of them commented out (see below)


Remaining known issues (also added as TODO notes):

- The hat and child profile flags are *overwritten* with the flags used
  for the main profile. (That's well-known behaviour from 2.8 :-/ but we
  have more flags now, which makes this more annoying.)
  The correct behaviour would be to add or remove the specified flag,
  while keeping other flags unchanged.

- Child profiles are not handled/changed if you specify the 'program'
  parameter. This means:
  - 'aa-complain smbldap-useradd' or 'aa-complain /usr/sbin/smbldap-useradd'
    _will not_ change the flags for the nscd child profile
  - 'aa-complain /etc/apparmor.d/usr.sbin.smbldap-useradd' _will_ change
    the flags for the nscd child profile (and any other profile and
    child profile in that file)


Even with those remaining issues (which need bigger changes in
set_profile_flags() and maybe also in the whole flags handling), the
patch improves things and fixes the regression from the 2.8 code.



Acked-by: Steve Beattie <steve@nxnw.org> for trunk and 2.9
2015-05-28 22:14:37 +02:00
Christian Boltz
682e23e1cd Enable testloops for nosetests
Ensure nosetests sees all tests in the tests[] tuples. This requires
some name changes because nosetests thinks all function names containing
"test" are tests. (A "not a test" docorator would be an alternative, but
that would require some try/except magic to avoid a dependency on nose.)

To avoid nosetests thinks the functions are a test,
- rename setup_all_tests() to setup_all_loops()
- rename regex_test() to _regex_test() (in test-regex_matches.py)

Also add the module_name as parameter to setup_all_loops and always run
it (not only if __name__ == '__main__').

Known issue: nosetests errors out with
    ValueError: no such test method in <class ...>: stub_test
when trying to run a single test generated out of tests[].
(debugging hint: stub_test is the name used in setup_test_loop().)
But that's still an improvement over not seeing those tests at all ;-)


Acked-by: Steve Beattie <steve@nxnw.org> for trunk and 2.9.
2015-04-22 22:01:34 +02:00
Christian Boltz
1f9474e653 fix handling of adding to variables
the LibreOffice profile uncovered that handling of @{var} += is broken:

  File ".../utils/apparmor/aa.py", line 3272, in store_list_var
    var[list_var] = set(var[list_var] + vlist)
TypeError: unsupported operand type(s) for +: 'set' and 'list'

This patch fixes it:
- change separate_vars() to use and return a set instead of a list
  (FYI: separate_vars() is only called by store_list_var())
- adoptstore_list_var() to expect a set
- remove some old comments in these functions
- explain the less-intuitive parameters of store_list_var()

Also add some tests for separate_vars() and store_list_var().
The tests were developed based on the old code, but not all of them
succeed with the old code.

As usual, the tests uncovered some interesting[tm] behaviour in
separate_vars() (see the XXX comments and tell me what the really
expected behaviour is ;-)


Acked-by: Steve Beattie <steve@nxnw.org> for trunk and 2.9
2015-04-16 01:58:24 +02:00
Christian Boltz
a313b674f7 simplify serialize_parse_profile_start()
Change serialize_parse_profile_start() to use parse_profile_start()
instead of using duplicated code.

The behaviour is mostly kept, with the exception that the function is
more strict now and raises exceptions instead of ignoring errors.

In practise, this won't change anything because the profiles are parsed
with parse_profile() (which calls parse_profile_start()) - and that
already errors out.

The tests are updated to match the more strict behaviour.


The next step would be to drop serialize_parse_profile_start()
completely, but this isn't urgent and can/should be done when we have
test coverage for serialize_profile_from_old_profile() one day ;-)


Acked-by: Steve Beattie <steve@nxnw.org>
2015-04-03 17:32:06 +02:00
Christian Boltz
0dc795d181 fix is_skippable_dir() and add tests
Fix is_skippable_dir() - the regex also matched things like
/etc/apparmor.d/dont_disable, while it should match on the full
directory name.

Also add some tests based on a real-world aa-logprof run (with "print (path)"
in is_skippable_dir()) and some additional "funny"[tm] dirs.

Needless to say that the tests
        ('dont_disable',                False),
        ('/etc/apparmor.d/cache_foo',   False),
will fail with the old is_skippable_dir().


Acked-by: Steve Beattie <steve@nxnw.org>
2015-04-03 17:29:44 +02:00
Christian Boltz
20cfa21695 replace RE_PROFILE_START
Replace RE_PROFILE_START with RE_PROFILE_START_2 and adjust all
code sections that used RE_PROFILE_START_2.

The only real change is that test_get_flags_invalid_01 and
test_get_flags_invalid_02 now expect AppArmorException instead of
AppArmorBug.


Acked-by: Steve Beattie <steve@nxnw.org> for trunk
2015-04-03 17:28:03 +02:00
Christian Boltz
a0a044f346 Finally implement attachment handling
This patch implements attachment handling - aa-logprof now works with
profiles that have an attachment defined, instead of ignoring audit.log
entries for those profiles.

Changes:
- parse_profile_start_line(): remove workaround that merged the
  attachment into the profile name
- parse_profile_data(): store attachment when parsing a profile
- update test_parse_profile_start_03, test_serialize_parse_profile_start_03,
  test_set_flags_nochange_09 and some parse_profile_start_line() tests -
  they now expect correct attachment handling


Acked-by: Steve Beattie <steve@nxnw.org>
2015-04-03 17:26:26 +02:00
Christian Boltz
bb3c972de9 [patch] make set_profile_flags more strict
this patch makes set_profile_flags more strict:
- raise AppArmorBug if newflags contains only whitespace
- raise AppArmorBug if the file doesn't contain the specified profile or
  no profile at all

The tests are adjusted to expect AppArmorBug instead of a silent
failure. Also, some tests are added for profile=None, which means to
change the flags for all profiles in a file.
- test_set_flags_08 is now test_set_flags_invalid_04
- test_set_flags_invalid_03 is changed to only contain one reason for a
  failure, not two ;-)


Acked-by: Steve Beattie <steve@nxnw.org>
2015-04-03 17:25:18 +02:00
Christian Boltz
38b1e3d30f rewrite set_profile_flags() to use write_header()
Changes in set_profile_flags():
- rewrite set_profile_flags to use parse_profile_start_line() and
  write_header().
- replace the silent failure for non-existing files with a proper
  exception (using lazy programming - the check is done by removing the
  "if os.path.isfile()" check, open_file_read then raises the
  exception ;-)
- comment out regex_hat_flag and the code that was supposed to handle
  hat flags, which were totally broken. We'll need another patch to fix
  it, and we also need to decide if we want to do that because it
  introduces a behaviour change (currently, aa-complain etc. don't
  change hat flags).

The tests for set_profile_flags() are also updated:
- prepend a space to comments because write_header always adds a space
  between '{' and the comment
- remove a test with superfluous quotes that are no longer kept (that's
  just a profile cleanup, so dropping that test is the easiest way)
- update test_set_flags_10 and test_set_flags_12 to use the correct
  profile name
- enable the tests for invalid (empty) flags
- update the test for a non-existing file

Note: test_set_flags_10, test_set_flags_12 and test_set_flags_nochange_09
will fail with this patch applied. The next patch will fix that.


Acked-by: Steve Beattie <steve@nxnw.org>
2015-04-03 17:20:14 +02:00
Christian Boltz
6651d4a3ee test new parameters of write_header()
Change the write_header tests so that the 'profile_keyword' and
'header_comment' parameters can be (and are) tested:
- add a None for both to the existing tests
- add some tests that come with the profile keyword and/or a comment


Acked-by: Steve Beattie <steve@nxnw.org>
2015-04-02 01:31:22 +02:00
Christian Boltz
b81400185d [patch] extend and partially rewrite write_header()
- add support for prof_data['header_comment'] (comment after '{')
  and prof_data['profile_keyword'] (to force the 'profile' keyword, even
  if it isn't needed) to write_header().
  (set_profile_flags() will be the only user of these two for now)

- fix a crash if depth is not an integer - for example,
      len('   ')/2   # 3 spaces = 1.5
  would cause a crash.
  Also add a test for 1.5 and 1.3 spaces.

- rewrite the handling of flags to avoid we have to maintain two
  different template lines.

- update the tests to set 'profile_keyword' and 'header_comment' to None.
  This avoids big changes in the test code. I'll send another patch that
  makes sure profile_keyword and header_comment are tested ;-)


Acked-by: Steve Beattie <steve@nxnw.org>
2015-04-02 01:30:01 +02:00
Christian Boltz
e0a8ed7673 add attachment to parse_profile_start() return values
Add the attachment to the parse_profile_start() and
serialize_parse_profile_start() return values, and adjust the functions
calling the *parse_profile_start() functions to save the attachment in
the "attachment" variable (which isn't used yet).

Also adjust the tests for the added return value.

(Sorry for not getting the resultset right from the beginning!)



Acked-by: Steve Beattie <steve@nxnw.org>
2015-04-01 23:58:29 +02:00
Christian Boltz
0478f6bb11 Add support for attachments to write_header()
Also fix a little bug that added the profile keyword if the path needed
quotes (profile "/foo bar" - but "/foo bar" is enough). This was caused
by a regex that always matched on quoted paths (hint: "/ matches
^[^/] ;-)

Also add some tests with attachments and update the test for the bugfix
mentioned above.


Now the remaining part is to make sure that prof_data['attachment'] gets
set when parsing the profiles :-)



Acked-by: Steve Beattie <steve@nxnw.org>
2015-04-01 23:50:04 +02:00
Christian Boltz
80e33751c9 add tests for write_header()
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>
2015-04-01 23:48:50 +02:00
Christian Boltz
35382be8d0 add tests for set_profile_flags() (and some fun)
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>
2015-04-01 23:43:29 +02:00
Christian Boltz
b8f0a5cbb2 convert serialize_parse_profile_start() to use parse_profile_start_line()
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>
2015-04-01 10:58:27 +02:00
Christian Boltz
90efcd7a92 add tests for serialize_parse_profile_start() to test-aa.py
to document the function's behaviour.

Acked-by: Steve Beattie <steve@nxnw.org>
2015-04-01 10:57:24 +02:00
Christian Boltz
4ad6f486f8 update test-aa.py to match parse_profile_start() and get_profile_flags() changes
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>
2015-03-31 22:45:45 +02:00
Christian Boltz
55a2809a5a aa.py: split off parse_profile_start() from parse_profile_data() and add tests
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>
2015-03-02 21:12:12 +01:00
Christian Boltz
c469b92afb Add some tests for aa.py get_profile_flags().
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>
2015-03-02 19:36:20 +01:00
Christian Boltz
9d471cdd73 Update is_skippable_file() to match all extensions that are listed in
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>
2015-02-04 13:16:29 +01:00
Christian Boltz
b1c28c7a23 Add some tests for aa.py check_for_apparmor()
Also change check_for_apparmor() to allow easier testing by optionally
specifying alternative locations for /proc/filesystems and /proc/mounts
as parameter.

Note that the code in check_for_apparmor() differs from what the comment
says - valid_path() only does syntax checks, but doesn't check if the
directory exists. I added a comment saying exactly that.


Acked-by: Steve Beattie <steve@nxnw.org>
2014-11-27 23:20:26 +01:00