2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-22 10:07:12 +00:00

parser: add support for conditional includes

This is a minimal patch to add conditional includes to the profile
language.

The syntax for conditional includes is similar to regular includes
except with the addition of "if exists" after "include"

  include if exists <foo/bar>
  include if exists "foo/bar"
  include if exists "/foo/bar"
  include if exists foo/bar

Note: The patch is designed to be backportable with minimum
effort. Cleanups and code refactoring are planned for follow up
patches that won't be back ported.

Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
John Johansen 2018-01-07 01:06:10 -08:00
parent 8d142809f5
commit 2ea3309942
48 changed files with 392 additions and 10 deletions

View File

@ -55,7 +55,7 @@ B<VARIABLE> = '@{' I<ALPHA> [ ( I<ALPHANUMERIC> | '_' ) ... ] '}'
B<ALIAS RULE> = 'alias' I<ABS PATH> '-E<gt>' I<REWRITTEN ABS PATH> ','
B<INCLUDE> = '#include' ( I<ABS PATH> | I<MAGIC PATH> )
B<INCLUDE> = ( '#include' | 'include' ) [ 'if exists' ] ( I<ABS PATH> | I<MAGIC PATH> )
B<ABS PATH> = '"' path '"' (the path is passed to open(2))
@ -1414,13 +1414,17 @@ rules into a rule block.
=head2 #include mechanism
AppArmor provides an easy abstraction mechanism to group common file
AppArmor provides an easy abstraction mechanism to group common
access requirements; this abstraction is an extremely flexible way to
grant site-specific rights and makes writing new AppArmor profiles very
simple by assembling the needed building blocks for any given program.
The use of '#include' is modelled directly after cpp(1); its use will
replace the '#include' statement with the specified file's contents.
The leading '#' is optional, and the '#include' keyword can be followed
by an option conditional 'if exists' that specifies profile compilation
should continue if the specified file or directory is not found.
B<#include "/absolute/path"> specifies that F</absolute/path> should be
used. B<#include "relative/path"> specifies that F<relative/path> should
be used, where the path is relative to the current working directory.

View File

@ -144,7 +144,7 @@ static int include_dir_cb(int dirfd unused, const char *name, struct stat *st,
return 0;
}
void include_filename(char *filename, int search)
void include_filename(char *filename, int search, bool if_exists)
{
FILE *include_file = NULL;
struct stat my_stat;
@ -161,11 +161,14 @@ void include_filename(char *filename, int search)
include_file = fopen(fullpath, "r");
}
if (!include_file)
if (!include_file) {
if (if_exists)
return;
yyerror(_("Could not open '%s'"),
fullpath ? fullpath: filename);
}
if (fstat(fileno(include_file), &my_stat))
if (fstat(fileno(include_file), &my_stat))
yyerror(_("fstat failed for '%s'"), fullpath);
if (S_ISREG(my_stat.st_mode)) {
@ -257,6 +260,7 @@ LT_EQUAL <=
%x UNIX_MODE
%x CHANGE_PROFILE_MODE
%x INCLUDE
%x INCLUDE_EXISTS
%%
@ -269,25 +273,44 @@ LT_EQUAL <=
}
%}
<INITIAL,SUB_ID_WS,INCLUDE,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
<INITIAL,SUB_ID_WS,INCLUDE,INCLUDE_EXISTS,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
{WS}+ { DUMP_PREPROCESS; /* Ignoring whitespace */ }
}
<INCLUDE>{
<INCLUDE_EXISTS>{
(\<([^"\>\t\r\n]+)\>|{QUOTED_ID}) { /* <filename> | "filename" */
autofree char *filename = strndup(yytext, yyleng - 1);
include_filename(filename + 1, *filename == '<');
include_filename(filename + 1, *filename == '<', true);
POP_NODUMP();
}
(\<{QUOTED_ID}\>) { /* <"filename"> */
autofree char *filename = strndup(yytext, yyleng - 2);
include_filename(filename + 2, true);
include_filename(filename + 2, true, true);
POP_NODUMP();
}
({IDS}|{QUOTED_ID}) { /* filename */
include_filename(yytext, 0);
include_filename(yytext, 0, true);
POP_NODUMP();
}
}
<INCLUDE>{
(\<([^"\>\t\r\n]+)\>|{QUOTED_ID}) { /* <filename> | "filename" */
autofree char *filename = strndup(yytext, yyleng - 1);
include_filename(filename + 1, *filename == '<', false);
POP_NODUMP();
}
(\<{QUOTED_ID}\>) { /* <"filename"> */
autofree char *filename = strndup(yytext, yyleng - 2);
include_filename(filename + 2, true, false);
POP_NODUMP();
}
({IDS}|{QUOTED_ID}) { /* filename */
include_filename(yytext, 0, false);
POP_NODUMP();
}
}
@ -533,6 +556,20 @@ LT_EQUAL <=
}
}
#include{WS}+if{WS}+exists/{WS}.*\r?\n {
/* Don't use PUSH() macro here as we don't want #include echoed out.
* It needs to be handled specially
*/
yy_push_state(INCLUDE_EXISTS);
}
include{WS}+if{WS}+exists/{WS} {
/* Don't use PUSH() macro here as we don't want #include echoed out.
* It needs to be handled specially
*/
yy_push_state(INCLUDE_EXISTS);
}
#include/.*\r?\n {
/* Don't use PUSH() macro here as we don't want #include echoed out.
* It needs to be handled specially
@ -681,4 +718,5 @@ unordered_map<int, string> state_names = {
STATE_TABLE_ENT(UNIX_MODE),
STATE_TABLE_ENT(CHANGE_PROFILE_MODE),
STATE_TABLE_ENT(INCLUDE),
STATE_TABLE_ENT(INCLUDE_EXISTS),
};

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
include if exists "simple_tests/include_tests/includes_okay_helper.include"
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
include if exists "../tst/simple_tests/include_tests/includes_okay_helper.include"
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
include if exists "./simple_tests/include_tests/includes_okay_helper.include"
}

View File

@ -0,0 +1,8 @@
#
#=DESCRIPTION include if existss testing - test some "odd" locations of include if existss
#=EXRESULT PASS
#
/does/not/exist {
/does/not/exist mr, include if exists <includes/base> /bin/true Px,
include if exists "../tst/simple_tests/include_tests/includes_okay_helper.include" include if exists <includes/base>
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of a directory
#=EXRESULT PASS
#
/does/not/exist {
include if exists <includes/base>
include if exists "simple_tests/includes/"
include if exists <includes/base>
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
include if exists simple_tests/include_tests/includes_okay_helper.include
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
include if exists ../tst/simple_tests/include_tests/includes_okay_helper.include
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
include if exists ./simple_tests/include_tests/includes_okay_helper.include
}

View File

@ -0,0 +1,8 @@
#
#=DESCRIPTION include if existss testing - test some "odd" locations of include if existss
#=EXRESULT PASS
#
/does/not/exist {
/does/not/exist mr, include if exists <includes/base> /bin/true Px,
include if exists ../tst/simple_tests/include_tests/includes_okay_helper.include include if exists <includes/base>
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of a directory
#=EXRESULT PASS
#
/does/not/exist {
include if exists <includes/base>
include if exists simple_tests/includes/
include if exists <includes/base>
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
include if exists "simple_tests/include_tests/includes with space helper.include"
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
include if exists "simple_tests/include_tests/includes with space helper.include" #comment
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
include if exists <"include_tests/includes with space helper.include">
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
include if exists <"include_tests/includes with space helper.include"> #comment
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
include if exists <include_tests/includes with space helper.include>
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
include if exists <include_tests/includes with space helper.include> #comment
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if exist testing - non-existent include should pass
#=EXRESULT PASS
#
/does/not/exist {
include if exists "does-not-exist/does-not-exist"
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if exists testing - abs path include does not exist should pass
#=EXRESULT PASS
#
/does/not/exist {
include if exists "/does-not-exist/does-not-exist"
}

View File

@ -0,0 +1,8 @@
#
#=DESCRIPTION include if exists testing - non-existent include should pass
#=EXRESULT PASS
#
/does/not/exist {
include <includes/base>
include if exists "../does-not-exist/does-not-exist"
}

View File

@ -0,0 +1,8 @@
#
#=DESCRIPTION include if exists testing - non-existent include should pass
#=EXRESULT PASS
#
/does/not/exist {
include <includes/base>
include if exists "../does-not-exist/does-not-exist"
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if exists testing - non-existent include should pass
#=EXRESULT PASS
#
/does/not/exist {
include if exists "does-not-exist/does-not-exist"
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if exists testing - non-existent include should pass
#=EXRESULT PASS
#
/does/not/exist {
include if exists <does-not-exist/does-not-exist>
}

View File

@ -0,0 +1,8 @@
#
#=DESCRIPTION include if exists testing - non-existent include should pass
#=EXRESULT PASS
#
/does/not/exist {
include if exists <does-not-exist/does-not-exist>
include <includes/base>
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
#include if exists "simple_tests/include_tests/includes_okay_helper.include"
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
#include if exists "../tst/simple_tests/include_tests/includes_okay_helper.include"
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
#include if exists "./simple_tests/include_tests/includes_okay_helper.include"
}

View File

@ -0,0 +1,8 @@
#
#=DESCRIPTION include if existss testing - test some "odd" locations of include if existss
#=EXRESULT PASS
#
/does/not/exist {
/does/not/exist mr, #include if exists <includes/base> /bin/true Px,
#include if exists "../tst/simple_tests/include_tests/includes_okay_helper.include" #include if exists <includes/base>
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of a directory
#=EXRESULT PASS
#
/does/not/exist {
#include if exists <includes/base>
#include if exists "simple_tests/includes/"
#include if exists <includes/base>
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
#include if exists simple_tests/include_tests/includes_okay_helper.include
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
#include if exists ../tst/simple_tests/include_tests/includes_okay_helper.include
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
#include if exists ./simple_tests/include_tests/includes_okay_helper.include
}

View File

@ -0,0 +1,8 @@
#
#=DESCRIPTION include if existss testing - test some "odd" locations of include if existss
#=EXRESULT PASS
#
/does/not/exist {
/does/not/exist mr, #include if exists <includes/base> /bin/true Px,
#include if exists ../tst/simple_tests/include_tests/includes_okay_helper.include #include if exists <includes/base>
}

View File

@ -0,0 +1,9 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of a directory
#=EXRESULT PASS
#
/does/not/exist {
#include if exists <includes/base>
#include if exists simple_tests/includes/
#include if exists <includes/base>
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
#include if exists "simple_tests/include_tests/includes with space helper.include"
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
#include if exists "simple_tests/include_tests/includes with space helper.include" #comment
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
#include if exists <"include_tests/includes with space helper.include">
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
#include if exists <"include_tests/includes with space helper.include"> #comment
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
#include if exists <include_tests/includes with space helper.include>
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if existss testing - basic include if exists of global and local include
#=EXRESULT PASS
#
/does/not/exist {
#include if exists <include_tests/includes with space helper.include> #comment
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if exist testing - non-existent include should pass
#=EXRESULT PASS
#
/does/not/exist {
#include if exists "does-not-exist/does-not-exist"
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if exists testing - abs path include does not exist should pass
#=EXRESULT PASS
#
/does/not/exist {
#include if exists "/does-not-exist/does-not-exist"
}

View File

@ -0,0 +1,8 @@
#
#=DESCRIPTION include if exists testing - non-existent include should pass
#=EXRESULT PASS
#
/does/not/exist {
#include <includes/base>
#include if exists "../does-not-exist/does-not-exist"
}

View File

@ -0,0 +1,8 @@
#
#=DESCRIPTION include if exists testing - non-existent include should pass
#=EXRESULT PASS
#
/does/not/exist {
#include <includes/base>
#include if exists "../does-not-exist/does-not-exist"
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if exists testing - non-existent include should pass
#=EXRESULT PASS
#
/does/not/exist {
#include if exists "does-not-exist/does-not-exist"
}

View File

@ -0,0 +1,7 @@
#
#=DESCRIPTION include if exists testing - non-existent include should pass
#=EXRESULT PASS
#
/does/not/exist {
#include if exists <does-not-exist/does-not-exist>
}

View File

@ -0,0 +1,8 @@
#
#=DESCRIPTION include if exists testing - non-existent include should pass
#=EXRESULT PASS
#
/does/not/exist {
#include if exists <does-not-exist/does-not-exist>
#include <includes/base>
}