[apparmor] [PATCH 05/11] parser: Allow change_profile rules to accept an exec mode modifier
Tyler Hicks
tyhicks at canonical.com
Wed May 25 20:59:37 UTC 2016
https://launchpad.net/bugs/1584069
This patch allows policy authors to specify how exec transitions should
be handled with respect to setting AT_SECURE in the new process'
auxiliary vector and, ultimately, having libc scrub (or not scrub) the
environment.
An exec mode of 'safe' means that the environment will be scrubbed and
this is the default in kernels that support AppArmor profile stacking.
An exec mode of 'unsafe' means that the environment will not be scrubbed
and this is the default and only supported change_profile exec mode in
kernels that do not support AppArmor profile stacking.
Signed-off-by: Tyler Hicks <tyhicks at canonical.com>
---
parser/parser_lex.l | 26 ++++++++++++++++++++++----
parser/parser_regex.c | 22 +++++++++++++++++-----
parser/parser_yacc.y | 28 ++++++++++++++++++++++++----
3 files changed, 63 insertions(+), 13 deletions(-)
diff --git a/parser/parser_lex.l b/parser/parser_lex.l
index 49b1f22..a49c7dd 100644
--- a/parser/parser_lex.l
+++ b/parser/parser_lex.l
@@ -255,6 +255,7 @@ LT_EQUAL <=
%x PTRACE_MODE
%x UNIX_MODE
%x CHANGE_PROFILE_MODE
+%x CHANGE_PROFILE_TARGET_MODE
%x INCLUDE
%%
@@ -268,7 +269,7 @@ LT_EQUAL <=
}
%}
-<INITIAL,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,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,CHANGE_PROFILE_TARGET_MODE,RLIMIT_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
{WS}+ { DUMP_PREPROCESS; /* Ignoring whitespace */ }
}
@@ -439,7 +440,16 @@ LT_EQUAL <=
}
<CHANGE_PROFILE_MODE>{
- {ARROW} { RETURN_TOKEN(TOK_ARROW); }
+ safe { RETURN_TOKEN(TOK_SAFE); }
+ unsafe { RETURN_TOKEN(TOK_UNSAFE); }
+
+ {ARROW} {
+ /**
+ * Push state so that we can return TOK_ID even when the
+ * change_profile target is 'safe' or 'unsafe'.
+ */
+ PUSH_AND_RETURN(CHANGE_PROFILE_TARGET_MODE, TOK_ARROW);
+ }
({IDS}|{QUOTED_ID}) {
yylval.id = processid(yytext, yyleng);
@@ -447,6 +457,13 @@ LT_EQUAL <=
}
}
+<CHANGE_PROFILE_TARGET_MODE>{
+ ({IDS}|{QUOTED_ID}) {
+ yylval.id = processid(yytext, yyleng);
+ POP_AND_RETURN(TOK_ID);
+ }
+}
+
<RLIMIT_MODE>{
-?{NUMBER} {
yylval.var_val = strdup(yytext);
@@ -619,7 +636,7 @@ include/{WS} {
PUSH_AND_RETURN(state, token);
}
-<INITIAL,NETWORK_MODE,RLIMIT_MODE,CHANGE_PROFILE_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
+<INITIAL,NETWORK_MODE,RLIMIT_MODE,CHANGE_PROFILE_MODE,CHANGE_PROFILE_TARGET_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
{END_OF_RULE} {
if (YY_START != INITIAL)
POP_NODUMP();
@@ -632,7 +649,7 @@ include/{WS} {
}
}
-<INITIAL,SUB_ID,SUB_VALUE,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
+<INITIAL,SUB_ID,SUB_VALUE,LIST_VAL_MODE,EXTCOND_MODE,LIST_COND_VAL,LIST_COND_PAREN_VAL,LIST_COND_MODE,EXTCONDLIST_MODE,ASSIGN_MODE,NETWORK_MODE,CHANGE_PROFILE_MODE,CHANGE_PROFILE_TARGET_MODE,MOUNT_MODE,DBUS_MODE,SIGNAL_MODE,PTRACE_MODE,UNIX_MODE>{
[^\n] {
DUMP_PREPROCESS;
/* Something we didn't expect */
@@ -663,5 +680,6 @@ unordered_map<int, string> state_names = {
STATE_TABLE_ENT(PTRACE_MODE),
STATE_TABLE_ENT(UNIX_MODE),
STATE_TABLE_ENT(CHANGE_PROFILE_MODE),
+ STATE_TABLE_ENT(CHANGE_PROFILE_TARGET_MODE),
STATE_TABLE_ENT(INCLUDE),
};
diff --git a/parser/parser_regex.c b/parser/parser_regex.c
index 8cc08c6..b8bf7fb 100644
--- a/parser/parser_regex.c
+++ b/parser/parser_regex.c
@@ -530,13 +530,13 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
* TODO: split link and change_profile entries earlier
*/
if (entry->deny) {
- if ((entry->mode & ~(AA_LINK_BITS | AA_CHANGE_PROFILE)) &&
+ if (!(entry->mode & (AA_LINK_BITS | AA_CHANGE_PROFILE)) &&
!dfarules->add_rule(tbuf.c_str(), entry->deny,
entry->mode & ~(AA_LINK_BITS | AA_CHANGE_PROFILE),
entry->audit & ~(AA_LINK_BITS | AA_CHANGE_PROFILE),
dfaflags))
return FALSE;
- } else if (entry->mode & ~AA_CHANGE_PROFILE) {
+ } else if (!(entry->mode & AA_CHANGE_PROFILE)) {
if (!dfarules->add_rule(tbuf.c_str(), entry->deny, entry->mode,
entry->audit, dfaflags))
return FALSE;
@@ -569,6 +569,7 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
autofree char *ns = NULL;
autofree char *name = NULL;
int index = 1;
+ uint32_t onexec_perms = AA_ONEXEC;
if ((warnflags & WARN_RULE_DOWNGRADED) && entry->audit && warn_change_profile) {
/* don't have profile name here, so until this code
@@ -610,12 +611,23 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
}
/* regular change_profile rule */
- if (!dfarules->add_rule_vec(entry->deny, AA_CHANGE_PROFILE | AA_ONEXEC, 0, index - 1, &vec[1], dfaflags))
+ if (!dfarules->add_rule_vec(entry->deny,
+ AA_CHANGE_PROFILE | onexec_perms,
+ 0, index - 1, &vec[1], dfaflags))
return FALSE;
+
/* onexec rules - both rules are needed for onexec */
- if (!dfarules->add_rule_vec(entry->deny, AA_ONEXEC, 0, 1, vec, dfaflags))
+ if (!dfarules->add_rule_vec(entry->deny, onexec_perms,
+ 0, 1, vec, dfaflags))
return FALSE;
- if (!dfarules->add_rule_vec(entry->deny, AA_ONEXEC, 0, index, vec, dfaflags))
+
+ /**
+ * pick up any exec bits, from the frontend parser, related to
+ * unsafe exec transitions
+ */
+ onexec_perms |= (entry->mode & (AA_EXEC_BITS | ALL_AA_EXEC_UNSAFE));
+ if (!dfarules->add_rule_vec(entry->deny, onexec_perms,
+ 0, index, vec, dfaflags))
return FALSE;
}
return TRUE;
diff --git a/parser/parser_yacc.y b/parser/parser_yacc.y
index 91c6d68..bb40f09 100644
--- a/parser/parser_yacc.y
+++ b/parser/parser_yacc.y
@@ -1474,11 +1474,31 @@ file_mode: TOK_MODE
free($1);
}
-change_profile: TOK_CHANGE_PROFILE opt_id opt_named_transition TOK_END_OF_RULE
+change_profile: TOK_CHANGE_PROFILE opt_unsafe opt_id opt_named_transition TOK_END_OF_RULE
{
struct cod_entry *entry;
- char *exec = $2;
- char *target = $3;
+ int mode = AA_CHANGE_PROFILE;
+ int exec_mode = $2;
+ char *exec = $3;
+ char *target = $4;
+
+ if (exec_mode) {
+ if (!exec)
+ yyerror(_("Exec condition is required when unsafe or safe keywords are present"));
+
+ if (exec_mode == 1) {
+ mode |= (AA_EXEC_BITS | ALL_AA_EXEC_UNSAFE);
+ } else if (exec_mode == 2 &&
+ !kernel_supports_stacking &&
+ warnflags & WARN_RULE_DOWNGRADED) {
+ pwarn("downgrading change_profile safe rule to unsafe due to lack of necessary kernel support\n");
+ /**
+ * No need to do anything because the 'unsafe'
+ * variant is the only supported type of
+ * change_profile rules in non-stacking kernels
+ */
+ }
+ }
if (exec && !(exec[0] == '/' || strncmp(exec, "@{", 2) == 0))
yyerror(_("Exec condition must begin with '/'."));
@@ -1492,7 +1512,7 @@ change_profile: TOK_CHANGE_PROFILE opt_id opt_named_transition TOK_END_OF_RULE
yyerror(_("Memory allocation error."));
}
- entry = new_entry(target, AA_CHANGE_PROFILE, exec);
+ entry = new_entry(target, mode, exec);
if (!entry)
yyerror(_("Memory allocation error."));
--
2.7.4
More information about the AppArmor
mailing list