Allow for a leading '&' character to be present in the named transition
target strings to indicate that the transition should stack the current
profile with the specified profile.

Signed-off-by: Tyler Hicks <[email protected]>
---
 parser/parser.h                                    |  2 +-
 parser/parser_lex.l                                |  5 +++--
 parser/parser_misc.c                               | 22 ++++++++++++++++++----
 parser/parser_yacc.y                               |  7 ++++++-
 .../simple_tests/change_profile/stacking_ok_1.sd   |  7 +++++++
 .../simple_tests/change_profile/stacking_ok_2.sd   |  7 +++++++
 .../simple_tests/change_profile/stacking_ok_3.sd   |  7 +++++++
 parser/tst/simple_tests/file/stacking_ok_1.sd      |  7 +++++++
 8 files changed, 56 insertions(+), 8 deletions(-)
 create mode 100644 parser/tst/simple_tests/change_profile/stacking_ok_1.sd
 create mode 100644 parser/tst/simple_tests/change_profile/stacking_ok_2.sd
 create mode 100644 parser/tst/simple_tests/change_profile/stacking_ok_3.sd
 create mode 100644 parser/tst/simple_tests/file/stacking_ok_1.sd

diff --git a/parser/parser.h b/parser/parser.h
index ab55a74..81f211a 100644
--- a/parser/parser.h
+++ b/parser/parser.h
@@ -386,7 +386,7 @@ extern char *process_var(const char *var);
 extern int parse_mode(const char *mode);
 extern int parse_X_mode(const char *X, int valid, const char *str_mode, int 
*mode, int fail);
 bool label_contains_ns(const char *label);
-void parse_label(char **ns, char **name, const char *label);
+void parse_label(bool *stack, char **ns, char **name, const char *label);
 extern struct cod_entry *new_entry(char *id, int mode, char *link_id);
 
 /* returns -1 if value != true or false, otherwise 0 == false, 1 == true */
diff --git a/parser/parser_lex.l b/parser/parser_lex.l
index e26b2b9..49b1f22 100644
--- a/parser/parser_lex.l
+++ b/parser/parser_lex.l
@@ -192,6 +192,7 @@ OPEN_BRACE  \{
 CLOSE_BRACE    \}
 SLASH          \/
 COLON          :
+AMPERSAND      &
 END_OF_RULE    [,]
 RANGE          -
 MODE_CHARS     ([RrWwaLlMmkXx])|(([Pp]|[Cc])[Xx])|(([Pp]|[Cc])?([IiUu])[Xx])
@@ -225,8 +226,8 @@ SET_VAR_PREFIX  @
 SET_VARIABLE   {SET_VAR_PREFIX}(\{{VARIABLE_NAME}\}|{VARIABLE_NAME})
 BOOL_VARIABLE  $(\{{VARIABLE_NAME}\}|{VARIABLE_NAME})
 
-LABEL          (\/|{SET_VARIABLE}{POST_VAR_ID}|{COLON}){ID}*
-QUOTED_LABEL   \"(\/|{SET_VAR_PREFIX}|{COLON})([^\0"]|\\\")*\"
+LABEL          (\/|{SET_VARIABLE}{POST_VAR_ID}|{COLON}|{AMPERSAND}){ID}*
+QUOTED_LABEL   \"(\/|{SET_VAR_PREFIX}|{COLON}|{AMPERSAND})([^\0"]|\\\")*\"
 
 OPEN_PAREN     \(
 CLOSE_PAREN    \)
diff --git a/parser/parser_misc.c b/parser/parser_misc.c
index aa29675..22f6fef 100644
--- a/parser/parser_misc.c
+++ b/parser/parser_misc.c
@@ -571,6 +571,7 @@ int parse_X_mode(const char *X, int valid, const char 
*str_mode, int *mode, int
 
 /**
  * parse_label - break a label down to the namespace and profile name
+ * @stack: Will be true if the first char in @label is '&' to indicate stacking
  * @ns: Will point to the first char in the namespace upon return or NULL
  *      if no namespace is present
  * @ns_len: Number of chars in the namespace string or 0 if no namespace
@@ -589,7 +590,8 @@ int parse_X_mode(const char *X, int valid, const char 
*str_mode, int *mode, int
  * 2) Namespace is empty meaning @label starts with "::"
  * 3) Profile name is empty
  */
-static int _parse_label(char **ns, size_t *ns_len,
+static int _parse_label(bool *stack,
+                       char **ns, size_t *ns_len,
                        char **name, size_t *name_len,
                        const char *label)
 {
@@ -597,6 +599,17 @@ static int _parse_label(char **ns, size_t *ns_len,
        const char *ns_start = NULL;
        const char *ns_end = NULL;
 
+       if (label[0] == '&') {
+               /**
+                * Leading ampersand means that the current profile should
+                * be stacked with the rest of the label
+                */
+               *stack = true;
+               label++;
+       } else {
+               *stack = false;
+       }
+
        if (label[0] != ':') {
                /* There is no namespace specified in the label */
                name_start = label;
@@ -639,15 +652,16 @@ static int _parse_label(char **ns, size_t *ns_len,
 
 bool label_contains_ns(const char *label)
 {
+       bool stack = false;
        char *ns = NULL;
        char *name = NULL;
        size_t ns_len = 0;
        size_t name_len = 0;
 
-       return _parse_label(&ns, &ns_len, &name, &name_len, label) == 0 && ns;
+       return _parse_label(&stack, &ns, &ns_len, &name, &name_len, label) == 0 
&& ns;
 }
 
-void parse_label(char **_ns, char **_name, const char *label)
+void parse_label(bool *_stack, char **_ns, char **_name, const char *label)
 {
        char *ns = NULL;
        char *name = NULL;
@@ -655,7 +669,7 @@ void parse_label(char **_ns, char **_name, const char 
*label)
        size_t name_len = 0;
        int res;
 
-       res = _parse_label(&ns, &ns_len, &name, &name_len, label);
+       res = _parse_label(_stack, &ns, &ns_len, &name, &name_len, label);
        if (res == 1) {
                yyerror(_("Namespace not terminated: %s\n"), label);
        } else if (res == 2) {
diff --git a/parser/parser_yacc.y b/parser/parser_yacc.y
index 69fa4ff..44793f7 100644
--- a/parser/parser_yacc.y
+++ b/parser/parser_yacc.y
@@ -305,14 +305,19 @@ opt_id_or_var: { /* nothing */ $$ = NULL; }
 profile_base: TOK_ID opt_id_or_var flags TOK_OPEN rules TOK_CLOSE
        {
                Profile *prof = $5;
+               bool self_stack = false;
 
                if (!prof) {
                        yyerror(_("Memory allocation error."));
                }
 
-               parse_label(&prof->ns, &prof->name, $1);
+               parse_label(&self_stack, &prof->ns, &prof->name, $1);
                free($1);
 
+               if (self_stack) {
+                       yyerror(_("Profile names must begin with a '/' or a 
namespace"));
+               }
+
                /* Honor the --namespace-string command line option */
                if (profile_ns) {
                        /**
diff --git a/parser/tst/simple_tests/change_profile/stacking_ok_1.sd 
b/parser/tst/simple_tests/change_profile/stacking_ok_1.sd
new file mode 100644
index 0000000..402bf78
--- /dev/null
+++ b/parser/tst/simple_tests/change_profile/stacking_ok_1.sd
@@ -0,0 +1,7 @@
+#
+#=DESCRIPTION change_profile w/ stacking
+#=EXRESULT PASS
+#
+/usr/bin/foo {
+   change_profile -> &/bin/foo,
+}
diff --git a/parser/tst/simple_tests/change_profile/stacking_ok_2.sd 
b/parser/tst/simple_tests/change_profile/stacking_ok_2.sd
new file mode 100644
index 0000000..9b616ae
--- /dev/null
+++ b/parser/tst/simple_tests/change_profile/stacking_ok_2.sd
@@ -0,0 +1,7 @@
+#
+#=DESCRIPTION change_profile w/ stacking
+#=EXRESULT PASS
+#
+/usr/bin/foo {
+   change_profile -> &bar,
+}
diff --git a/parser/tst/simple_tests/change_profile/stacking_ok_3.sd 
b/parser/tst/simple_tests/change_profile/stacking_ok_3.sd
new file mode 100644
index 0000000..cb4f3a3
--- /dev/null
+++ b/parser/tst/simple_tests/change_profile/stacking_ok_3.sd
@@ -0,0 +1,7 @@
+#
+#=DESCRIPTION change_profile w/ stacking
+#=EXRESULT PASS
+#
+/usr/bin/foo {
+   change_profile /bin/foo -> &bar,
+}
diff --git a/parser/tst/simple_tests/file/stacking_ok_1.sd 
b/parser/tst/simple_tests/file/stacking_ok_1.sd
new file mode 100644
index 0000000..f1e747e
--- /dev/null
+++ b/parser/tst/simple_tests/file/stacking_ok_1.sd
@@ -0,0 +1,7 @@
+#
+#=Description basic file exec rule with stacking target
+#=EXRESULT PASS
+#
+/usr/bin/foo {
+  /bin/bar px -> &baz,
+}
-- 
2.7.0


-- 
AppArmor mailing list
[email protected]
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/apparmor

Reply via email to