parser/tst/simple_tests/profile/profile_ns_bad8.sd was added in r3376
(trunk) / r3312 (2.10 branch) and contains the profile name ':ns/t'
which misses the terminating ':' for the namespace.
Unfortunately the tools don't understand namespaces yet and just use the
full profile name. This also means this test doesn't fail as expected
when tested against the utils code.
This patch adds profile_ns_bad8.sd to the exception list of
test-parser-simple-tests.py.
Acked-by: Steve Beattie <steve@nxnw.org> for trunk and 2.10.
https://launchpad.net/bugs/1546455
Don't filter out AF_UNSPEC from the list of valid protocol families so
that the parser will accept rules such as 'network unspec,'.
There are certain syscalls, such as socket(2), where the LSM hooks are
called before the protocol family is validated. In these cases, AppArmor
was emitting denials even though socket(2) will eventually fail. There
may be cases where AF_UNSPEC sockets are accepted and we need to make
sure that we're mediating those appropriately.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Suggested-by: Steve Beattie <steve@nxnw.org>
Acked-by: John Johansen <john.johansen@canonical.com>
[cboltz: Add 'unspec' to the network domain keywords of the utils]
If a profile file contains multiple profiles, aa-mergeprof crashes on
saving in write_profile() because the second profile in the file is not
listed in 'changed'. (This happens only if the second profile didn't
change.)
This patch first checks if 'changed' contains the profile before
pop()ing it.
Reproducer: copy utils/test/cleanprof_test.in to your profile directory
and run aa-mergeprof utils/test/cleanprof_test.out. Then just press
's' to save the profile.
Acked-by: Kshitij Gupta <kgupta8592@gmail.com> for trunk, 2.10 and 2.9
If autodep() is called with a pname starting with / (which can happen
for (N)amed exec depending on the user input), this pname is mapped to
bin_name.
This might look like a good idea, however if the given pname doesn't
exist as file on-disk, autodep() returns None instead of a (mostly
empty) profile. (Reproducer: choose (N)amed, enter "/foo/bar")
Further down the road, this results in two things:
a) the None result gets written as empty profile file (with only a "Last
modified" line)
b) a crash if someone chooses to add an abstraction to the None, because
None doesn't support the delete_duplicates() method for obvious
reasons ;-)
Unfortunately this patch also introduces a regression - aa-logprof now
fails to follow the exec and doesn't ask about the log events for the
exec target anymore. However this doesn't really matter because of a) -
asking and saving to /dev/null vs. not asking isn't a real difference
;-)
Actually the patch slightly improves things - it creates a profile for
the exec target, but only with the depmod() defaults (abstractions/base)
and always in complain mode.
I'd prefer a patch that also creates a complete profile for the exec
target, but that isn't as easy as fixing the issues mentioned above and
therefore is something for a future fix. To avoid we forget it, I opened
https://bugs.launchpad.net/apparmor/+bug/1545155
Note: 2.9 "only" writes an empty file and doesn't crash - but writing
an empty profile is still an improvement.
Acked-by: Kshitij Gupta <kgupta8592@gmail.com> for trunk, 2.10 and 2.9
Most probably-file log events can also be network events. Therefore
check for request_mask in all events, not only file_perm, file_inherit
and (from the latest bugreport) file_receive.
References: https://bugs.launchpad.net/apparmor/+bug/1540562
Acked-by: Kshitij Gupta <kgupta8592@gmail.com> for trunk, 2.10 and 2.9.
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>
This makes it easier to find the file that contains a failing test.
Acked-by: Steve Beattie <steve@nxnw.org> for trunk and 2.10.
Bug: https://launchpad.net/bugs/1526085
When hitting an unknown line while parsing a profile, it's a good idea
to include that line in the error message ;-)
Note: 2.9 would print a literal \n because it doesn't have apparmor.fail,
so it will get a slightly different patch with spaces instead of \n.
Acked-by: Steve Beattie <steve@nxnw.org> for trunk, 2.10 and 2.9.
Bug: https://launchpad.net/bugs/1525119
If a *Ruleset is empty, let __repr__() print/return
<FooRuleset (empty) />
instead of
<FooRuleset>
</FooRuleset>
Acked-by: Steve Beattie <steve@nxnw.org> for trunk and 2.10.
Bug: https://launchpad.net/bugs/1523297
'!' is a reserved symbol and needs to be escaped in AARE.
Note: aare.py only exists in trunk, therefore this part is trunk-only.
Acked-by: Seth Arnold <seth.arnold@canonical.com> for trunk, 2.10 and 2.9 as needed.
If parse_event_for_tree() raises an AppArmorException (for example
because of an invalid/unknown request_mask), catch it in read_log() and
re-raise it together with the log line causing the Exception.
Acked-by: Steve Beattie <steve@nxnw.org> for trunk, 2.10 and 2.9.
handle_children() has some special code for handling link events with
denied_mask = 'l'. Unfortunately this special code depends on a regex
that matches the old, obsolete log format - in a not really parsed
format ("^from .* to .*$").
The result was that aa-logprof did not ask about events containing 'l'
in denied_mask.
Fortunately the fix is easy - delete the code with the special handling
for 'l' events, and the remaining code that handles other file
permissions will handle it :-)
References: Bugreport by pfak on IRC
Testcase (with hand-tuned log event):
aa-logprof -f <( echo 'Jan 7 03:11:24 mail kernel: [191223.562261] type=1400 audit(1452136284.727:344): apparmor="ALLOWED" operation="link" profile="/usr/sbin/smbd" name="/foo" pid=10262 comm=616D617669736420286368362D3130 requested_mask="l" denied_mask="l" fsuid=110 ouid=110 target="/bar"')
should ask to add '/foo l,' to the profile.
Acked-by: Seth Arnold <seth.arnold@canonical.com> for trunk, 2.10 and 2.9.
r2637 added support for parsing unix rules, but forgot to add write
support. The result was that a profile lost its unix rules when it was
saved.
This patch adds the write_unix_rules() and write_unix() functions (based
on the write_pivot_root() and write_pivot_root_rules() functions) and
makes sure they get called at the right place.
The cleanprof testcase gets an unix rule added to ensure it's not
deleted when writing the profile. (Note that minitools_test.py is not
part of the default "make check", however I always run it.)
References: https://bugs.launchpad.net/apparmor/+bug/1522938https://bugzilla.opensuse.org/show_bug.cgi?id=954104
Acked-by: Tyler Hicks <tyhicks@canonical.com> for trunk, 2.10 and 2.9.
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.
python 3 uses only the 'str' type, while python 2 also uses 'unicode'.
This patch adds a type_is_str() function to common.py - depending on the
python version, it checks for both. This helper function is used to keep
the complexity outside of the rule classes.
The rule classes get adjusted to use type_is_str() instead of checking
for type(x) == str, which means they support both python versions.
Finally, add test-common.py with some tests for type_is_str().
References: https://bugs.launchpad.net/apparmor/+bug/1513880
Acked-by: Tyler Hicks <tyhicks@canonical.com> for trunk and 2.10
Note: 2.10 doesn't contain SignalRule and aare.py, and rule/__init__.py
doesn't have check_and_split_list(), therefore it doesn't get those
parts of the patch.
Don't catch AppArmorExceptions in aa-easyprof any longer and rely on
apparmor.fail to print the exception to stderr.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Christian Boltz <apparmor@cboltz.de>
The patch also switches to using error() instead of a plain print() for
AppArmorException, which means prefixing the error message with 'ERROR: '
References: https://bugs.launchpad.net/apparmor/+bug/1521400
Acked-by: Tyler Hicks <tyhicks@canonical.com> for trunk and 2.10.
'change_hat' events have the target profile in 'name2', not in 'name'
(which is None and therefore causes a crash when checking if it contains
'//')
Also add the log event causing this crash to the libapparmor testsuite.
References: https://bugs.launchpad.net/apparmor/+bug/1523297
Acked-by: John Johansen <john.johansen@canonical.com> for trunk, 2.10 and 2.9.
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.
As Kshitij mentioned, abstract methods should use NotImplementedError
instead of AppArmorBug.
While changing this, I noticed that __repr__() needs to be robust against
NotImplementedError because get_raw() is not available in BaseRule.
Therefore the patch changes __repr__() to catch NotImplementedError.
Of course the change to NotImplementedError also needs several
adjustments in the tests.
Acked-by: Kshitij Gupta <kgupta8592@gmail.com>
(long before branching off 2.10, therefore I also commit to 2.10)
Note: 2.10 doesn't have test-signal.py, which means it can't be patched ;-)
Creating a file is in theory covered by the 'a' permission, however
discussion on IRC brought up that depending on the open flags it might
not be enough (real-world example: creating the apache pid file).
Therefore change the mapping to 'w' permissions. That might allow more
than needed in some cases, but makes sure the profile always works.
Acked-by: Kshitij Gupta <kgupta8592@gmail.com> for 2.9, 2.10 and trunk
For debugging, it's helpful to know which part of the code initialized a
profile_storage and for which profile and hat this was done.
This patch adds an 'info' array with that information, adds the
corresponding parameters to profile_storage() and changes the callers to
deliver some useful content.
Acked-by: John Johansen <john.johansen@canonical.com> for trunk and 2.10
We replaced parse_audit_allow() with parse_modifiers() in r2833, but
overlooked that parse_modifiers() returns allow/deny as boolean. This
resulted in storing bare file rules in aa[profile][hat]['path'][False]
instead of aa[profile][hat]['path']['allow'] (or True instead of 'deny'
for 'deny file,' rules), with the user-visible result of loosing bare
file rules when saving the profile.
This patch converts the boolean value from parse_modifiers back to a
string.
Note: 2.9 is not affected because the old parse_audit_allow() returns
'allow' or 'deny' as string, not as boolean.
Acked-by: Kshitij Gupta <kgupta8592@gmail.com> for trunk and 2.10
The last utils/test/Makefile change switched to using the in-tree
libapparmor by default (unless USE_SYSTEM=1 is given). However, I missed
to add the swig/python parts of libapparmor to PYTHONPATH, so the
system-wide LibAppArmor/__init__.py was always used.
This patch adds the in-tree libapparmor python module to PYTHONPATH.
I'm sorry for the interesting[tm] way to find out that path, but
a) I don't know a better / less ugly way and
b) a similar monster already works in libapparmor/swig/python/test/ ;-)
Acked-by: John Johansen <john.johansen@canonical.com> for 2.9 and trunk
(that also implies 2.10 ;-)
To make things more interesting, /usr/bin/python and /usr/bin/python[23]
are symlinks to /usr/bin/python[23].[0-9], so we have to explicitely
list several versions.
Acked-by: John Johansen <john.johansen@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com> for 2.9, 2.10 and trunk
This makes print()ing a class object much more helpful - instead of
<apparmor.rule.network.NetworkRule object at 0x7f416b239e48>
we now get something like
<NetworkRule> network inet stream,
(based on get_raw())
A NetworkRuleset will be printed as (also based on get_raw())
<NetworkRuleset>
network inet stream,
allow network inet stream, # comment
</NetworkRuleset>
Also add tests to test-network.py to ensure that __repr__() works as
expected.
Acked-by: Kshitij Gupta <kgupta8592@gmail.com>
This patch checks if the cfg object is empty (happens if logprof.conf
doesn't exist). If so, it adds some empty sections to prevent various
failures in code that expects those sections to exist.
Another source of failures was using cfg['section']['setting']. The
patch changes various places to cfg['section'].get('setting') to prevent
those failures. (Those places all have a 'or ...' fallback.)
Finally, find_first_file() in config.py crashed if file_list was Null.
This is fixed by adding an "if file_list:" check before trying to
split() it.
With all those changes applied, 'make check' will work even if
/etc/apparmor/logprof.conf doesn't exist.
The patch also fixes the default value for inactive_profiledir
(I missed aa.py when I changed it to /usr/share/apparmor/extra-profiles/)
References: https://bugs.launchpad.net/apparmor/+bug/1393979
Acked-by: John Johansen <john.johansen@canonical.com>
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
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
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>
Also add support for the USE_SYSTEM variable, which means:
- test against the in-tree libapparmor and python modules by default
- test against the system libapparmor and python modules if USE_SYSTEM
is set
The old behaviour was a mix of both - it always used the in-tree python
modules and the system libapparmor.
For obvious reasons, you'll need to build libapparmor before running the
tests (unless you specify USE_SYSTEM=1 as parameter to make check).
Acked-by: John Johansen <john.johansen@canonical.com> for trunk and 2.9
Add a testcase that parses all tests in the parser/tst/simple_tests/
directory with parse_profile_data() to ensure that everything with valid
syntax is accepted, and that all tests marked as FAIL raise an
exception.
This already resulted in
- several patches to fix low-hanging fruits (including some bugs in the
parser simple_tests itsself)
- a list of tests that don't behave as expected. Those files get their
expected result reverted to make sure we notice any change in the
tools behaviour, especially changing to the really expected resulted.
This method also makes sure that the testcase doesn't report any of
the known failures.
- a 5% improvement in test coverage - mostly caused by nearly completely
covering parse_profile_data.
- addition of some missing testcased (as noticed by missing coverage),
for example several "rule outside of a profile" testcases.
As indicated above, the tools don't work as expected on all test
profiles - most of the failures happen on expected-to-fail tests that
pass parse_profile_data() without raising an exception. There are also
some tests failing despite valid syntax, often with rarely used syntax
like if conditions and qualifier blocks.
Most of the failing (generated) tests are caused by features not
implemented in the tools yet:
- validating dbus rules (currently we just store them without any parsing)
- checks for conflicting x permissions
- permissions before path ("r /foo,")
- 'safe' and 'unsafe' keywords for *x rules
- 'Pux' and 'Cux' permissions (which actually mean PUx and CUx, and get
rejected by the tools - ideally the generator script should create
PUx and CUx tests instead)
skip_startswith excludes several generated tests from being run. I know
that skip_startswith also excludes tests that would not fail, but the
generated filenames (especially generated_x/exact-*) don't have a
pattern that I could easily use to exclude less tests - and I'm not too
keen to add a list with 1000 single filenames ;-)
Acked-by: John Johansen <john.johansen@canonical.com>
The global variable 'logger' in aa.py is only used by aa-genprof.
This patch changes aa_genprof to use the (new) logger_path() function,
and moves the code for finding the logger path to that function.
Also make the error message more helpful if logger can't be found.
Acked-by: John Johansen <john.johansen@canonical.com>
The 'ldd' variable in aa.py is only used by get_reqs(), therefore move
setting it (based on the configfile) into the function.
get_reqs() doesn't run too often (only called by create_new_profile(),
which means aa-genprof or when adding a Px or Cx rule to a non-existing
profile). This might even lead to a minor performance win - on average,
I'd guess not every aa-logprof run will lead to a completely new profile
or child profile. And, more important, we get rid of a global variable.
Acked-by: John Johansen <john.johansen@canonical.com>
create_new_profile() didn't init missing required_hats as
profile_storage(), which might lead to crashes when creating a profile
for an application listed in the required_hats config option (= in very
rare cases).
This patch adds the missing profile_storage() call.
Acked-by: Kshitij Gupta <kgupta8592@gmail.com>
This also means the duplicate detection can use the hat's filename instead
of the (possibly wrong) main profile's filename.
Acked-by: Kshitij Gupta <kgupta8592@gmail.com>
With this addition, all globbing styles (as documented in apparmor.d(5))
are covered in the convert_regexp() tests.
Acked-by: Seth Arnold <seth.arnold@canonical.com>
load_include() used a custom os.listdir call instead of
include_dir_filelist() for directory includes, which means it also read
skippable files like *.rpmnew or README. (It seems nobody created a
README inside an included directory, otherwise we'd have seen a
bugreport ;-)
This patch changes load_include() to use include_dir_filelist(). This
function is used in some more places already and removes skippable files
from the file list.
Acked-by <timeout>
load_include() has a "if not incdata:" block which would be entered if
parse_profile_data() returns None. However, parse_profile_data() always
returns a hasher with [incfile][incfile] = profile_storage(), so that
"if not incdata:" never matches.
Acked-by <timeout>
The "already loaded?" check in load_include() was done at the beginning
of the function, before entering the loop and before the individual
files of directory includes were added to the filelist. This resulted in
a (wrong) "Conflicting profiles" error for directory includes.
This patch moves the "alreay loaded?" check inside the loop, so that
it's executed for all files, including those of directory includes.
Acked-by <timeout>
TL;DR: aa-genprof crashes with a wrong 'Conflicting profiles' error.
aa-genprof uses autodep() to create a basic profile, which is then
stored in aa and original_aa. After that, read_profiles() is called,
which reads all profiles (including the new one) from disk, causing a
(wrong) 'Conflicting profiles' error in attach_profile_data() because
the autodep()-generated profile is already there.
Therefore this patch resets aa and original_aa in read_profiles() to
avoid that problem.
Acked-by <timeout>
The tests for convert_regexp() were hidden in common_test.py, where they
were never executed.
This patch moves them to the new file test-aare.py and also converts the
regex_tests.ini to a tests[] array to have the test data inside the test
file. (All tests from regex_tests.ini are in test-aare.py, and two tests
with prepended and appended path segments were added.)
Also add some tests that check the raw behaviour of convert_regexp() -
the tests "by example" are probably more useful and for sure more
readable ;-) but I want to have some examples of the converted regexes
available.
Acked-by <timeout>
logparser.py does a regex check on log lines as performance improvement
so that it only hands over lines that look like AppArmor events to
LibAppArmor parsing. Those regexes were incomplete and didn't cover all
log formats LibAppArmor accepts, with the end result of "overlooking"
events.
This patch splits off common parts of the regex, adds more regexes for
several log types and finally merges everything into one regex.
test-libapparmor-test_multi.py now also checks all test_multi log lines
against the regex to ensure logparser.py doesn't silently ignore events.
test-logparser.py gets adjusted to the merged RE_LOG_ALL regex.
Finally, add a new test that was posted on IRC to the test_multi set.
As already threatened nearly a month ago,
Acked by <timeout> for trunk and 2.9
This testcase will parse all libraries/libapparmor/testsuite/test_multi
tests and compare the result with the *.out files.
It also include a "ToDo list" of keywords that are not yet supported in
the python code - those are typically related to rule types not
supported in the tools yet (dbus, signal etc.).
An interesting special case are exec events with network details:
testcase01.in, testcase12.in, testcase13.in
which might be hand-made, invalid logs, but nobody remembers ;-)
Acked-by <timeout>