This will simplify add new features as most of the code can reside in
its own class. There are still things to improve but its a start.
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Steve Beattie <steve@nxnw.org>
The valgrind test script would happily chug along even if if valgrind
was not installed, not doing anything of use. This patch fixes that, and
offers up the ability to specify an alternate location for valgrind if
it does not exist in the usual /usr/bin location.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
It was never used, never supported, and we are doing it differently now.
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
The parser currently indicates that it exited successfully if invalid
arguments are passed to it, which makes it difficult to detect when
other tools are calling it incorrectly. This patch causes it to return
'1' indicating a failure.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: John Johansen <john.johansen@canonical.com>
When passing an include directory on the command line to
apparmor_parser, valgrind emits a warning:
Invalid read of size 4
at 0x404DA6: add_search_dir(char const*) (parser_include.c:152)
by 0x40BB37: process_arg(int, char*) (parser_main.c:457)
by 0x403D43: main (parser_main.c:590)
Address 0x572207c is 28 bytes inside a block of size 29 alloc'd
at 0x4C2A420: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
by 0x53E31C9: strdup (strdup.c:42)
by 0x404D94: add_search_dir(char const*) (parser_include.c:145)
by 0x40BB37: process_arg(int, char*) (parser_main.c:457)
by 0x403D43: main (parser_main.c:590)
This patch quiets the warning by removing strlen() calls on the t char
array. Instead, it only calls strlen() on the dir char array. t is a
dupe of dir and strlen(dir) does not trigger the valgrind warning.
Additionally, this patch adds a bit of defensive programming to the
while loop to ensure that index into the t array is never negative.
Finally, the valgrind suppression is removed from valgrind_simple.py.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Steve Beattie <steve@nxnw.org>
With commit 2364 addressing one of valgrind's false positives, we can
remove the related valgrind suppression entry from the test script.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
Acked-by: Tyler Hicks <tyhicks@canonical.com>
strlen() assumes that it can read an entire word but when a char array
does not end on a word boundary, it reads past the end of the array.
This results in the following valgrind warning:
Invalid read of size 4
at 0x40A162: yylex() (parser_lex.l:277)
by 0x40FA14: yyparse() (parser_yacc.c:1487)
by 0x40C5B9: process_profile(int, char const*) (parser_main.c:1003)
by 0x404074: main (parser_main.c:1340)
Address 0x578d870 is 16 bytes inside a block of size 18 alloc'd
at 0x4C2A420: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
by 0x53E31C9: strdup (strdup.c:42)
by 0x40A145: yylex() (parser_lex.l:276)
by 0x40FA14: yyparse() (parser_yacc.c:1487)
by 0x40C5B9: process_profile(int, char const*) (parser_main.c:1003)
by 0x404074: main (parser_main.c:1340)
This patch quiets the warning by not using strlen(). This can be done
because yyleng already contains the length of string.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Steve Beattie <steve@nxnw.org>
When the --cache-loc option was added in trunk commit 1916, it was
intended that -L would be the short form of the option (based on
documentation and usage changes). However, the commit mistakenly
did not include the short option in the list include in the call
to getopt_long(3). This patch adds it along with the indicator
that it requires an argument (the different cache location) to the
getopt_long() call.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
includes come out like
#include
##included <tunables/home>
which is wrong because #include by itself is broken, and since -p is
supposed to be removing includes, it should not be directly echoed
any keyword in the keyword table is double echoed
ownerowner /{run,dev}/shm/pulse-shm* rwk
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Steve Beattie <steve@nxnw.org>
This patch adds support for the rttime rlimit (aka RLIMIT_RTTIME),
available since the 2.6.25 kernel, according to the getrlimit(2)
man page; see that man page for more details on this rlimit.
An acceptance test is also added, as well as an update to the
apparmor.vim input template.
While reviewing to see what made sense in apparmor.vim for the rttime
rlimit, I discovered that RLIMIT_RTTIME's units are microseconds, not
seconds like RLIMIT_CPU (according to the setrlimit(2) manpage). This
necessitated not sharing the case switch with RLIMIT_CPU. I didn't add
a keyword for microseconds, but I did for milliseconds. I also don't
accept any unit larger than minutes, as it didn't seem appropriate
(and even minutes felt... gratuitous). I would appreciate feedback
on what keywords would be useful here.
Patch History:
v1: initial submission
v2: - add apparmor.vim support for rttime keyword
- adjust RLIMIT_TIME value assignment due to its units being
microseconds, not seconds, and add milliseconds keyword.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: John Johansen <john.johansen@canonical.com>
Close file handle left opened if parser.cfg is found and read from.
Found by cppcheck.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: John Johansen <john.johansen@canonical.com>
Fix leaked memory if calloc() fails. Found by cppcheck.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: John Johansen <john.johansen@canonical.com>
Seth Arnold noticed an ugly string.clear(); convert_entry(string,
NULL) pattern occurred frequently following the conversion to using
std::string. This patch replaces that by using a static pointer to
a constant string matching pattern, and also converts other uses of
that pattern. It also adds a function wrapper that will clear the
passed buffer before calling convert_entry().
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: John Johansen <john.johansen@canonical.com>
As noted by Seth Arnold, in expand_by_alternations() if our set
variable has at least one value, then we're going to rewrite the entry,
so rather than sprinkle the free()s near where the reallocation occurs,
use one free() once we're guaranteed to need to do so.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: John Johansen <john.johansen@canonical.com>
As suggested by Seth Arnold, we can use string::find_last_not_of()
instead of using C++'s hideous reverse iterators.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: John Johansen <john.johansen@canonical.com>
As noted by Seth Arnold, e_buffer_overflow is no longer set in
convert_aaregex_to_pcre(), so remove it and the sole check for it.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: John Johansen <john.johansen@canonical.com>
This patch converts a stack allocated buffer into an std::ostringstream
object. The stringstream interface for specifying the equivalent of
a printf %02x conversion is a bit of an awkward construction, however.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: John Johansen <john.johansen@canonical.com>
Based on feedback from Seth Arnold, the convert_aaregex_to_pcre()'s
first argument is const char *, and thus the unit test macros don't need
to pass a copy of the input string to it, as it's guaranteed to be
unmodified by the function.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: John Johansen <john.johansen@canonical.com>
This patch eliminates the bison warning about "%name-prefix =" being
deprecated.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: John Johansen <john.johansen@canonical.com>
Current builds include many warnings when building translations message
files like so:
msgfmt -c -o ja.mo ja.po
ja.po:5: warning: header field 'Language' missing in header
According to what I read in the entry for Language in
http://www.gnu.org/software/gettext/manual/gettext.html#Header-Entry
the language entry should be (in our case) the same as the file name
minus the .po suffix. This patch adds the language field for those
po files that were missing it.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Christian Boltz <apparmor@cboltz.de>
This patch adds several assorted language tests, to exercise various
parts of the parser that were not being covered by the language tests
previously. Areas lacking were found using the coverage compilation
option; coverage from the language tests is still incomplete.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Christian Boltz <apparmor@cboltz.de>
This patch updates the Report-Msgid-Bugs-To: to point to the apparmor
list instead of the old Novell forge address. It also makes the
Project-Id-Version: field consistent.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Christian Boltz <apparmor@cboltz.de>
The parser was lacking language tests for rlimits. This test adds
several, one for each rlimit type.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Christian Boltz <apparmor@cboltz.de>
As noted by Seth Arnold, there's now only one failure case in the
function and thus does not warrant a goto target (especially since
there's no cleanup to occur).
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Christian Boltz <apparmor@cboltz.de>
Subtle change to remove the "..." between the test description and
result and also to single-space the output. This brings the output in
line with what minimize.sh outputs, which is the test that runs just
before equality.sh.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: John Johansen <john.johansen@canonical.com>
This test ensures that the proper DFA minimization occurs when a
permissive D-Bus abstraction #include's the corresponding strict
abstraction.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-By: Christian Boltz <apparmor@cboltz.de>
std::max in C++ requires that both arguments be the same type. The
previous fix added std::max comparisons between unsigned long numeric
constants and size_t, this fix casts the numeric constants to size_t.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: John Johansen <john.johansen@canonical.com>
Tests should be added for other rule types but this is a good start at
testing DFA minimization.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: John Johansen <john.johansen@canonical.com>
Acked-By: Christian Boltz <apparmor@cboltz.de>
Make the accept information dump output be in hexidecimal like the
other dumps so its easier to reference between them.
Signed-off-by: John Johansen <john.johansen@canonical.com>
This was part of the original minimization patch, but got dropped when
applying to bzr. Again bzr status didn't show any files out of place
nor did the patching fail :(
Signed-off-by: John Johansen <john.johansen@canonical.com>
This diff is part of the diffencode patch but was dropped when it was
applied to bzr. I have no idea why and status showed a clean tree.
Signed-off-by: John Johansen <john.johansen@canonical.com>
So DFA minimization has a bug and feature that keeps it from minimizing
some dfas completely. This feature/bug did not result in incorrect dfas,
it just fails to result in full minimization.
The same mappings comparison is wrong. Or more correctly it is right when
transitions are not remapped to minimization partitions, but it may be
wrong when states are remapped. This means it will cause excess
partitioning (not removing all the states it should).
The trans hashing does a "guess" at partition splitting as a performance
enhancement. Basically it leverages the information that states that have
different transitions or transitions on different characters are not the
same. However this isn't always the case, because minimization can cause
some of those transitions to be altered. In previous testing this was
always a win, with only a few extra states being added some times. However
this changes with when the same mappings are fixed, as the hashing that was
done was based on the same flawed mapping as the broken same mappings.
If the same mappings are fixed and the hashing is not removed then there
is little to no change. However with both changes applied some dfas see
significant improvements. These improvements often result in performance
improvements despite minimization doing more work, because it means less
work to be done in the chfa comb compression
eg. test case that raised the issue (thanks tyler)
/t { mount fstype=ext2, mount, }
used to be minimized to
{1} <== (allow/deny/audit/quiet)
{6} (0x 2/0/0/0)
{1} -> {2}: 0x7
{2} -> {3}: 0x0
{2} -> {2}: []
{3} -> {4}: 0x0
{3} -> {3}: []
{4} -> {6}: 0x0
{4} -> {7}: 0x65 e
{4} -> {5}: []
{5} -> {6}: 0x0
{5} -> {5}: []
{6} (0x 2/0/0/0) -> {6}: [^\0x0]
{7} -> {6}: 0x0
{7} -> {8}: 0x78 x
{7} -> {5}: []
{8} -> {6}: 0x0
{8} -> {5}: 0x74 t
{8} -> {5}: []
with the patch it is now properly minimized to
{1} <== (allow/deny/audit/quiet)
{6} (0x 2/0/0/0)
{1} -> {2}: 0x7
{2} -> {3}: 0x0
{2} -> {2}: []
{3} -> {4}: 0x0
{3} -> {3}: []
{4} -> {6}: 0x0
{4} -> {4}: []
{6} (0x 2/0/0/0) -> {6}: [^\0x0]
The evince profile set sees some significant improvements picking a couple
example from its "minimized" dfas (it has 12) we see a reduction from 9720
states to 6232 states, and 6537 states to 3653 states. All told seeing the
performance/profile size going from
2.8 parser: 4.607s 1007267 bytes
dev head: 3.48s 1007267 bytes
min fix: 2.68s 549603 bytes
of course evince is an extreme example so a few more
firefox
2.066s 404549 bytes
to
1.336s 250585 bytes
cupsd
0.365s 90834 bytes
to
0.293s 58855 bytes
dnsmasq
0.118s 35689 bytes
to
0.112s 27992 bytes
smbd
0.187s 40897 bytes
to
0.162s 33665 bytes
weather applet profile from ubuntu touch
0.618s 105673 bytes
to
0.432s 89300 bytes
I have not seen a case where the parser regresses on performance but it is
possible. This patch will not cause a regression on generated policy size,
at worst it will result in policy that is the same size
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Steve Beattie <steve@nxnw.org>
Differential state compression encodes a state's transitions as the
difference between the state and its default state (the state it is
relative too).
This reduces the number of transitions that need to be stored in the
transition table, hence reducing the size of the dfa. There is a
trade off in that a single input character may have to traverse more
than one state. This is somewhat offset by reduced table sizes providing
better locality and caching properties.
With carefully encoding we can still make constant match time guarentees.
This patch guarentees that a state that is differentially encoded will do at
most 3m state traversal to match an input of length m (as opposed to a
non-differentially compressed dfa doing exactly m state traversals).
In practice the actually number of extra traversals is less than this becaus
we selectively choose which states are differentially encoded.
In addition to reducing the size of the dfa by reducing the number of
transitions that have to be stored. Differential encoding reduces the
number of transitions that need to be considered by comb compression,
which can result in tighter packing, due to a reduction in sparseness, and
also reduces the time spent in comb compression which currently uses an
O(n^2) algorithm.
Differential encoding will always result in a DFA that is smaller or equal
in size to the encoded DFA, and will usually improve compilation times,
with the performance improvements increasing as the DFA gets larger.
Eg. Given a example DFA that created 8991 states after minimization.
* If only comb compression (current default) is used
52057 transitions are packed into a table of 69591 entries. Achieving an
efficiency of about 75% (an average of about 7.74 table entries per state).
With a resulting compressed dfa16 size of 404238 bytes and a run time for
the dfa compilation of
real 0m9.037s
user 0m8.893s
sys 0m0.036s
* If differential encoding + comb compression is used, 8292 of the 8991
states are differentially encoded, with 31557 trans removed. Resulting in
20500 transitions are packed into a table of 20675 entries. Acheiving an
efficiency of about 99.2% (an average of about 2.3 table entries per state
With a resulting compressed dfa16 size of 207874 bytes (about 48.6%
reduction) and a run time for the dfa compilation of
real 0m5.416s (about 40% faster)
user 0m5.280s
sys 0m0.040s
Repeating with a larger DFA that has 17033 states after minimization.
* If only comb compression (current default) is used
102992 transitions are packed into a table of 137987 entries. Achieving
an efficiency of about 75% (an average of about 8.10 entries per state).
With a resultant compressed dfa16 size of 790410 bytes and a run time for d
compilation of
real 0m28.153s
user 0m27.634s
sys 0m0.120s
* with differential encoding
39374 transition are packed into a table of 39594 entries. Achieving an
efficiency of about 99.4% (an average of about 2.32 entries per state).
With a resultant compressed dfa16 size of 396838 bytes (about 50% reduction
and a run time for dfa compilation of
real 0m11.804s (about 58% faster)
user 0m11.657s
sys 0m0.084s
Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
By default, statically link against the in-tree libapparmor. If the
in-tree libapparmor is not yet built, print a helpful error message. To
build against the system libapparmor, the USE_SYSTEM make
variable can be set on the command line like so:
$ make USE_SYSTEM=1
This patch also fixes issues around the inclusion of the apparmor.h
header. Previously, the in-tree apparmor.h was always being included
even if the parser was being linked against the system libapparmor.
It modifies the apparmor.h include path based on the previous patch
separating them out in the libapparmor source. This was needed because
header file name collisions were already occurring.
For source files needing to include apparmor.h, the make targets were
also updated to depend on the local apparmor.h when building against
the in-tree libapparmor. When building against the system libapparmor,
the variable used in the dependency list is empty. Likewise, a
libapparmor.a dependency is added to the apparmor_parser target when
building against the in-tree apparmor.
Patch history:
v1: from Tyler Hicks <tyhicks@canonical.com>
- initial version
v2: revert to altering the include search path rather than including
the apparmor.h header directly via cpp arguments, alter the
include statements to <sys/apparmor.h> which will work against
either in-tree or (default) system paths.
v3: convert controlling variable to USE_SYSTEM from SYSTEM_LIBAPPARMOR
to unify between the parser and the regression tests.
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Signed-off-by: Steve Beattie <steve@nxnw.org>
With the previous patch to switch to using alternations for variable
expansion, the clone_and_chain set of functions are no longer needed
and no longer need to be passed around. This patch removes them.
(I kept this patch separate to keep the previous patch smaller and more
easily reviewed.)
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
This patch converts the parser's variable expansion from adding new
entries for each additional variable value to incorporating an
alternation that includes all the values for the variable; e.g. given:
@{BINS}=/bin /usr/bin /sbin /usr/sbin
@{BINS}/binary ix,
rather than expanding to exntries for
/bin/binary
/usr/bin/binary
/sbin/binary
/usr/sbin/binary
one entry would remain that looks like:
{/bin,/usr/bin,/sbin,/usr/sbin}/binary
One complication with this patch is that we try to prevent mistakes for
our users with variable expansion around '/'s; it's common for people to
write profiles that contain things like:
@{BAR}=/bingo/*/ /bango/
/foo/@{BAR}/baz
We already have a post-processing step that walks entries looking
for multiple sequences of '/'s and filters them into single
'/' which worked when creating new entries for each variable
expansion. Converting to alternation expansion breaks this filtering,
so code is added that removes leading and trailing slashes in variable
values in the expansion if the character immediately preceding or
following the variable is also a slash.
The intent behind this is to reduce the amount of memory allocations
and structure walking that needed to occur in when converting from the
entry strings to the back end nodes. Examples with real world profiles
showed performance improvements ranging from 2.5% to 10%. However,
because the back end operations are sensitive to the front end inputs,
it is possible for worse results to occur; for example, it takes the
simple_tests/vars/vars_stress_0[123].sd tests significantly longer to
complete after this patch is applied (vars_stress_03.sd in particular
takes ~23 times longer). An initial analysis of profiling output in
this negative case looks like it causes the tree simplification in
the back end to do more work for unknown reasons.
On the other hand, the test simple_tests/vars/vars_dbus_9.sd
(introduced in "[patch 09/12] parser: more dbus variable testcases")
takes ~1 sec to complete on my laptop before this patch, and roughly
0.01s with this patch applied.
(One option would be to keep the "expand entries" approach as an
alternative, but I couldn't come up with a good heuristic for when
to use it instead.)
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
This patch addresses the FIXMEs from the last patch by converting
process_mnt_entry's typebuf from a char[] to std::string. As a side
effect, the code in build_list_val_expr() is greatly simplified.
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
This patch removes the string length limit in convert_aaregex_to_pcre()
usage. One of the benefits to moving to C++ is the ability to use
std::strings, which dynamically resize themselves. While it's a large
patch, a non-trivial amount is due to needing to get a char * string
back out via the c_str() method.
The unit tests are modified to include checks to ensure that
convert_aaregex_to_pcre only appends to the passed pcre string,
it never resets it.
As the test case with overlong alternations added in the previous
patch now passes, the TODO status is removed from it.
(Note: there's a couple of FIXME comments related to converting typebuf
to std::string that are added by this patch that are addressed in the
next patch. I kept that conversion separate to try to reduce the size
of this patch a little.)
Signed-off-by: Steve Beattie <steve@nxnw.org>
Acked-by: Seth Arnold <seth.arnold@canonical.com>