Besides adding this feature, this also fixes a crash in tools.py __init__():
AttributeError: 'Namespace' object has no attribute 'do_reload'
Acked-by: Steve Beattie <steve@nxnw.org>
create_new_profile() created a wrong structure for local_profile, which
resulted in an aa-genprof crash directly at startup (in the autodep
phase).
This patch fixes it to use the correct structure.
Acked-by: Steve Beattie <steve@nxnw.org>
cux and CUx are valid exec permissions, so they should be accepted
by validate_profile_mode() ;-)
Acked-by: John Johansen <john.johansen@canonical.com> for trunk and 2.9
- allow only a specific set of time units
- optionally allow whitespace between rlimit value and unit
- move check for invalid time units to time_to_int()
Also update the tests:
- add several tests with whitespace between value and unit
- change a test that used the (now invalid) "1m" to "1min"
- change the time_to_int() tests to use 'us' as default unit, and add
a test with 'seconds' as default unit
Acked-by: Steve Beattie <steve@nxnw.org>
aa-logprof raises an exception if
- an include file contains a hat
- that file is included in a profile and
- aa-logprof hits an audit log entry for this profile
Reproducer ("works" on 2.9 and trunk):
python3 aa-logprof -f <(echo 'Jun 19 11:50:36 piorun kernel: [4474496.458789] audit: type=1400 audit(1434707436.696:153): apparmor="DENIED" operation="open" profile="/usr/sbin/apache2" name="/etc/gai.conf" pid=2910 comm="apache2" requested_mask="r" denied_mask="r" fsuid=0 ouid=0') -d ../profiles/apparmor.d/
This happens because profiles/apparmor.d/apache2.d/phpsysinfo was
already read when pre-loading the include files.
This patch changes aa.py parse_profile_data() to only raise the
exception if it is not handling includes currently.
Acked-by: Steve Beattie <steve@nxnw.org> for both trunk and 2.9.
is_known_rule() ignored directory includes, which resulted in asking for
and adding superfluous rules that are already covered by a file in the
included directory.
This patch looks bigger than it is because it moves quite some lines
into the "else:" branch. Everything inside the "else:" just got an
additional whitespace level.
References: https://bugs.launchpad.net/apparmor/+bug/1471425
(however, trunk didn't crash, it "just" ignored directory includes)
Acked-by: Steve Beattie <steve@nxnw.org>
is_known_rule() in aa.py checked only direct includes, but not includes
in the included files. As a result, aa-logprof asked about things that
are already covered by an indirect include.
For example, the dovecot/auth profile includes abstractions/nameservice,
and abstractions/nameservice includes abstractions/nis, which contains
"capability net_bind_service,".
Nevertheless, aa-logprof asked to add capability net_bind_service.
Reproducer: (asks for net_bind_service without this patch, should not
ask for anything after applying the patch):
python3 aa-logprof -d ../profiles/apparmor.d/ -f <(echo 'type=AVC msg=audit(1415403814.628:662): apparmor="ALLOWED" operation="capable" profile="/usr/lib/dovecot/auth" pid=15454 comm="auth" capability=13 capname="net_bind_service"')
The patch adds code to check include files included by other include
files. Note that python doesn't allow to change a list while looping
over it, therefore we have to use "while includelist" as workaround.
This fixes a regression for network rules (this patch is based on the
old match_net_include() code). Funnily it "only" fixes capability rule
handling (without the "regression" part) because the old
match_cap_include() didn't do the recursive include handling.
Acked-by: Steve Beattie <steve@nxnw.org>
For some (not yet known) reason, we get file_perm events without
request_mask set, which causes an aa-logprof crash.
Reproducer log entry:
Jun 19 12:00:55 piorun kernel: [4475115.459952] audit: type=1400 audit(1434708055.676:19629): apparmor="ALLOWED" operation="file_perm" profile="/usr/sbin/apache2" pid=3512 comm="apache2" laddr=::ffff:193.0.236.159 lport=80 faddr=::ffff:192.168.103.80 fport=61985 family="inet6" sock_type="stream" protocol=6
This patch changes logparser.py to ignore those events.
References: https://bugs.launchpad.net/apparmor/+bug/1466812/
Acked-by: Steve Beattie <steve@nxnw.org> for trunk and 2.9
According to the parser test profiles (which are the only
"documentation" I found about this), definition of boolean variables
is only allowed outside profiles, not inside them.
parse_profile_data() got it the wrong way round, therefore this patch
fixes the condition and updates the error message.
Acked-by: Steve Beattie <steve@nxnw.org> for both trunk and 2.9.
We need directory listings for #include <directory> in more than one
place, therefore split it off to its own function.
This is a preparation to fix https://bugs.launchpad.net/apparmor/+bug/1471425
Acked-by: Steve Beattie <steve@nxnw.org>
Thanks to a bug in the apparmor.d manpage, NetworkRule rejected rules
that contained only TYPE (for example "network stream,"). A bugreport on
IRC and some testing with the parser showed that this is actually
allowed, so NetworkRule should of course allow it.
Note: not strip()ing rule_details is the easiest way to ensure we have
whitespace in front of the TYPE in TYPE-only rules, which is needed by
the RE_NETWORK_DETAILS regex.
Also adjust the tests to the correct behaviour.
Acked-by: Steve Beattie <steve@nxnw.org>
Instead of always showing a backtrace,
- for AppArmorException (used for profile syntax errors etc.), print only
the exceptions value because a backtrace is superfluous and would
confuse users.
- for other (unexpected) exceptions, print backtrace and save detailed
information in a file in /tmp/ (including variable content etc.) to
make debugging easier.
This is done by adding the apparmor.fail module which contains a custom
exception handler (using cgitb, except for AppArmorException).
Also change all python aa-* tools to use the new exception handler.
Note: aa-audit did show backtraces only if the --trace option was given.
This is superfluous with the improved exception handling, therefore this
patch removes the --trace option. (The other aa-* tools never had this
option.)
If you want to test the behaviour of the new exception handler, you can
use this script:
#!/usr/bin/python
from apparmor.common import AppArmorException, AppArmorBug
from apparmor.fail import enable_aa_exception_handler
enable_aa_exception_handler()
# choose one ;-)
raise AppArmorException('Harmless example failure')
#raise AppArmorBug('b\xe4d bug!')
#raise Exception('something is broken!')
Acked-by: Seth Arnold <seth.arnold@canonical.com>
As shown in parser/tst/simple_tests/profile/flags/flags_ok_whitespace.sd,
the parser is quite tolerant to additional or missing whitespace around
flags=, while the tools are more strict.
This patch updates the RE_PROFILE_START regex to follow this tolerance.
Acked-by: Steve Beattie <steve@nxnw.org>.
The only difference between PROFILE_MODE_RE and PROFILE_MODE_NT_RE
was that the latter one additionally allowed 'x', which looks wrong.
(Standalone 'x' is ok for deny rules, but those are handled by
PROFILE_MODE_DENY_RE.)
This patch completely drops PROFILE_MODE_NT_RE and the related code in
validate_profile_mode().
Also wrap the two remaining regexes in '^(...)+$' instead of doing it
inside validate_profile_mode(). This makes the code more readable and
also results in a 2% performance improvement when parsing profiles.
Acked-by: Steve Beattie <steve@nxnw.org> for trunk and 2.9.
Add the missing "pux" to PROFILE_MODE_RE and PROFILE_MODE_NT_RE.
Also move those regexes and PROFILE_MODE_DENY_RE directly above
validate_profile_mode() which is the only user.
Acked-by: Steve Beattie <steve@nxnw.org> for trunk and 2.9
Parsing of boolean assignments failed with
TypeError: '_sre.SRE_Match' object is not subscriptable
because of a missing ".groups()"
Acked-by: Steve Beattie <steve@nxnw.org> for trunk and 2.9
RlimitRule accidently used 'ms' (milliseconds) as default unit for
rttime rules, but rttime without unit means 'us' (microseconds). This
patch fixes this.
Also add some tests with 'us' as unit, and two more to cover terribly
invalid corner cases (and to improve test coverage by 2 lines ;-)
Acked-by: John Johansen <john.johansen@canonical.com>
Acked-by: Steve Beattie <steve@nxnw.org>
Change minitools tests to use AATest and work inside a tmpdir.
This results in lots of changes ('./profiles' -> self.profile_dir,
local_profilename -> self.local_profilename etc.) and also moves some
code from the global area to AASetup().
Also drop the no longer needed clean_profile_dir() and add linebreaks
in assert* calls with a long error message specified.
Acked-by: Steve Beattie <steve@nxnw.org>
LSMs, such as AppArmor, aren't consulted when a program calls access(2).
This can result in access(2) returning 0 but a subsequent open(2)
failing.
The aa-status utility was doing the access() -> open() sequence and we
became aware of a large number of tracebacks due to open() failing for
lack of permissions. This patch catches any IOError exceptions thrown by
open(). It continues to print the same error message as before when
access() failed but also prints that error message when AppArmor blocks
the open of the apparmorfs profiles file.
https://launchpad.net/bugs/1466768
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Steve Beattie <steve@nxnw.org>
The function is basically a wrapper around a regex, so regex.py is a
much better home.
While on it, rename the regex to RE_INCLUDE, change it to named matches,
use RE_EOL to handle comments and compile it outside the function, which
should result in a (small) performance improvement.
Also rewrite re_match_include(), let it check for empty include
filenames ("#include <>") and let it raise AppArmorException in that
case.
Finally, adjust code calling it to the new location, and add some tests
for re_match_include()
Acked-by: Kshitij Gupta <kgupta8592@gmail.com>
profile_storage() returns an empty, properly initialized profile.
It doesn't explicitly init all keys (yet) and will be extended over
time, with the final goal to get rid of hasher().
Also change various places in aa.py to use it (instead of an empty
hasher or sub-hasher), and remove various "init rule class (if not done
yet)" cases.
This also avoids a crash in aa-cleanprof remove_duplicate_rules().
Hats weren't properly initialized in aa.py parse_profile_data()
(especially rule classes were missing), which caused a crash because
hasher doesn't support the delete_duplicates() method.
Acked-by: Kshitij Gupta <kgupta8592@gmail.com>
Change hat declarations ("^hat,") are no longer supported (see previous
patch for details). Therefore remove support for writing them.
This also means to completely remove the 'declared' flag, which was only
needed for hat declarations, and was (after the previous patch) always
set to False.
Also add a hat to the cleanprof_test.{in,out} test profile to make sure
aa-cleanprof doesn't break hats, and a hat declaration with the same
name to make sure it gets removed and doesn't break the "real" hat.
Acked-by: Kshitij Gupta <kgupta8592@gmail.com>
Hat declarations ("^hat,") were added in 2.3 for declaring external
hats, but in the meantime aren't supported by the parser anymore (tested
with 2.9.2 parser).
Additionally, if a profile contains both a hat declaration and the hat
("^hat { ...}"), the hat declaration can overwrite the content of the
hat on a "last one wins" base.
This is caused by setting 'declared' to True, which means write_piece()
will only write the "^hat," line, but not the "^hat { ... }" block.
Therefore no longer set 'declared' to True, print a warning that hat
declarations are no longer supported, and ignore the rule. This also
means that running aa-cleanprof can make the profile valid again :-)
Also no longer change 'hat' when hitting a profile declaration, which
also looks wrong.
Note: This change removes the only usage of 'declared'. A follow-up
patch (trunk only) will completely remove the 'declared' handling.
Reproducer profile (run aa-cleanprof on it):
(will crash in remove_duplicate_rules() 80% of the time - if so, try
multiple times. One of the next patches will fix that. Or just try 2.9,
which doesn't have the crash in remove_duplicate_rules().)
/usr/bin/true {
^FOO {
capability setgid,
}
# deletes the content of ^FOO when saving the profile! (last one wins)
# additionally, the parser says this is invalid syntax
^FOO,
}
See also the "Hat declarations" thread on the ML,
https://lists.ubuntu.com/archives/apparmor/2015-June/008107.html
Acked-by: Kshitij Gupta <kgupta8592@gmail.com> for both 2.9 and trunk.
Change aa.py to use RlimitRule and RlimitRuleset instead of a sub-hasher
to store and write rlimit rules. In detail:
- drop all rlimit rule parsing from parse_profile_data() and
serialize_profile_from_old_profile() - instead, just call
RlimitRule.parse()
- change write_rlimits() to use RlimitRuleset
- add removal of superfluous/duplicate change_profile rules (the old
code didn't do this)
- update the comment about aa[profile][hat] usage - rlimit and
change_profile are no longer dicts.
Also cleanup RE_PROFILE_RLIMIT in regex.py - the parenthesis around
'<=' are no longer needed.
Note: This patch is quite small because aa-logprof doesn't ask for
rlimit rules.
I tested all changes manually with aa-cleanprof and aa-logprof (adding
some file rules, rlimit rules kept unchanged)
Acked-by: Kshitij Gupta <kgupta8592@gmail.com>
Add two variable references (aa and changed) in aa-mergeprof
ask_the_questions() so that the code can use the short name and be more
in sync with aa.py ask_the_questions().
With this patch applied, the "for ruletype in ['capability', 'network']:"
block is in sync, with the exception of the sections that intentionally
differ:
- the check for the profile mode
- the default button selection based on profile mode
- the seen_events counter
The patch also includes some minor whitespace fixes.
Acked-by: Steve Beattie <steve@nxnw.org>
The following patch:
- removes re import
- uses apparmor.re_match_include instead of the regex
which also means to use the correct regex instead of
the slightly wrong one cleanprofile.py had
Acked-by: Christian Boltz <apparmor@cboltz.de>
The cleanprofile.py has an apparmor import, this patch modifies the import to make it consistent with the rest of modules.
Acked-by: Christian Boltz <apparmor@cboltz.de>
The following patch:
- Brings the return to the correct indentation
- Adds a sorted call over the set keys of hat in the profile
Acked-by: Christian Boltz <apparmor@cboltz.de> for trunk and 2.9.
After switching to winbindd as test profile, comments about the ntpd
profile don't make sense anymore ;-)
The patch also includes some whitespace fixes.
Acked-by: Kshitij Gupta <kgupta8592@gmail.com>
Acked-by: Steve Beattie <steve@nxnw.org>
This time we only have 98% coverage (some missing and partial) because
I didn't find corner cases that raise some exceptions ;-)
Acked-by: Steve Beattie <steve@nxnw.org>
The class comes with the usual set of features, so I'll only mention a
special feature: the is_covered() and is_equal() functions can even
compare limits with different units (for example they recognize that
2minutes == 120seconds).
Also change RE_PROFILE_RLIMIT:
- make it a bit more strict (the old one accepted any chars, including
spaces, for rlimit and value)
- convert it to named matches
- '<=' isn't optional - remove the '?' (but keep the parenthesis to
avoid breaking parsing in aa.py)
- allow rules with no spaces around '<='
Acked-by: Steve Beattie <steve@nxnw.org>
aa-cleanprof (actually clean_profile() in tools.py) used reload_base()
from aa.py which sends the parser output to /dev/null. This had two
effects:
- aa-cleanprof ignored the --no-reload parameter
- there was no error message because reload_base() /dev/null's the
parser output
This patch changes clean_profile() to use reload_profile() from tools.py
(which honors the --no-reload option).
Also add a TODO note to aa.py reload_base(), the (AFAIK only) winner of
the 'useless use of cat' award in the AppArmor code.
We should really change it to use reload_profile(), even if that means
moving the function from tools.py to aa.py or common.py. And it should
not /dev/null the apparmor_parser output. ;-)
References: https://bugs.launchpad.net/apparmor/+bug/1443637
Acked-by: Steve Beattie <steve@nxnw.org>
aa-complain is part of the enforce/complain/disable triple. Therefore
I expect it to actually load a profile in complain mode.
To do this, it has to delete the 'disable' symlink, but set_complain()
in aa.py didn't do this (and therefore kept the profile disabled).
Acked-by: Kshitij Gupta <kgupta8592@gmail.com>
Users might expect that setting a profile into audit mode also activates
it (which shouldn't happen IMHO because the audit flag is not part of
the enforce/complain/disable triple), so we should at least tell them.
References: https://bugs.launchpad.net/apparmor/+bug/1429448
Acked-by: Kshitij Gupta <kgupta8592@gmail.com>
aa-complain, aa-enforce, aa-disable and aa-audit refused to change
profiles for non-existing binaries. This patch also allows paths
starting with /. This also makes it possible to use
aa-complain '/{usr/,}bin/ping'
and
aa-complain /etc/apparmor.d/bin.ping
This patch fixes https://bugs.launchpad.net/apparmor/+bug/1416346
Well, mostly - we still need to decide how we handle wildcards in
profile names:
aa-complain ping
aa-complain /usr/bin/ping
will still error out with "Profile not found" because it isn't an exact
match (and matching the wildcard would change more than the user wants).
Oh, and this patch also fixes the last failure in minitools_test.py.
Acked-by: Steve Beattie <steve@nxnw.org> for trunk and 2.9
Change minitools_test.py to use the winbind instead of the ntpd profile
for testing. The tests broke because the ntpd profile has the
attach_disconnected flag set now, and therefore didn't match the
expected flags anymore.
Also replace the usage of filecmp.cmp() in the cleanprof test with
reading the file and using assertEqual - this has the advantage that we
get a full diff instead of just "files differ".
Note: The aa-cleanprof test is still failing because of a bug in
tools.py, but will be fixed by the next patch.
See https://bugs.launchpad.net/apparmor/+bug/1416346 for details.
Acked-by: Kshitij Gupta <kgupta8592@gmail.com>
This allows to run minitools_test.py as non-root user.
Also add a check that only creates the force-complain directory if it
doesn't exist yet.
Note: With this patch applied, there are still 4 failing tests, probably
caused by changes in the profiles that are used in the tests.
Acked-by: Kshitij Gupta <kgupta8592@gmail.com>
Add a --no-reload parameter to aa-audit, aa-cleanprof, aa-complain,
aa-disable and aa-enforce. This makes it possible to change the
profile flags without reloading the profile.
Also change tools.py to honor the --no-reload parameter.
References: https://bugs.launchpad.net/apparmor/+bug/1458480
Acked-by: Kshitij Gupta <kgupta8592@gmail.com>
Acked-by: Steve Beattie <steve@nxnw.org> for trunk and 2.9.
--fixes lp:1458480
The function will return the 'Exec Condition' and the 'Target Profile'
as nice list to use in aa-logprof (once we have support for
change_profile in logparser.py) and aa-mergeprof.
Also add some tests to ensure the correct result.
Acked-by: Steve Beattie <steve@nxnw.org>
This allows to drop the "apparmor.aa." prefix in ask_the_question() to
get the code more in sync with aa.py ask_the_question().
Acked-by: Steve Beattie <steve@nxnw.org>
Replace the code in aa.py ask_the_questions() that handles network rules
with the ask_the_questions() code initially copied from aa-mergeprof.
This means to convert the network/netdomain log events to a
NetworkRuleset stored in the log_obj hasher, and then let the code from
aa-mergeprof operate on this hasher.
The user interface is mostly unchanged, with two exceptions:
- options always displayed, even if there is only one option
- some slightly changed texts
If you didn't understand why there's a need for the previous patch, this
one should explain it :-)
This also ends up fixing at least one bug where the 'audit' keyword
wasn't listed as a separate qualifier, but instead showed up smooshed
into the Network Family header.
Acked-by: Steve Beattie <steve@nxnw.org>
Replace the code in aa.py ask_the_questions() that handles capabilities
with the ask_the_questions() code from aa-mergeprof.
This means to convert the capability log events to a CapabilityRuleset
stored in the (new) log_obj hasher, and then let the code from
aa-mergeprof operate on this hasher.
Most of the code after the "aa-mergeprof also has this code" comment is
a direct copy of the aa-mergeprof code, with the following changes:
- filter for profile mode (enforce/complain)
- set default button (allow or deny) based on profile mode
- keep seen_events counter happy (even if it isn't displayed anywhere)
- replace apparmor.aa.foo with just foo
The user interface is mostly unchanged, with two exceptions:
- options always displayed, even if there is only one option
- some slightly changed texts
Acked-by: Steve Beattie <steve@nxnw.org>