[apparmor] [patch 2/2] parser: add implicit set variable @{profile_name} to profile symbol table

Steve Beattie steve at nxnw.org
Fri Mar 28 18:15:51 UTC 2014


parser: add implicit set variable @{profile_name} to profile symbol table

This patch adds the creation of an implicit set variable
@{profile_name} for use within policy. It expands to:

  - a given profile name if specified; e.g. for
      'profile flappy_bird /some/pattern/match* { [...] }'
    @{profile_name} would expand to 'flappy_bird'
  - if no given name, the match pattern; e.g. for
      '/usr/bin/doge_bird { [...] }'
    @{profile_name} would expand to '/usr/bin/doge_bird'
  - hats and child profiles will include the fully qualified name; e.g.
    the 'doge' hat in the /usr/bin/flappy_bird profile would cause
    @{profile_name} to expand to '/usr/bin/flappy_bird//doge' within the
    'doge' hat, and '/usr/bin/flappy_bird' outside of it in the profile.

There are some parsing tests added, but more tests are needed to verify
that expansion occurs properly (I've verified manually using parser
dumps of the added tests, but automated checks are needed).

[A side question is whether a @{profile_hatname} or
@{profile_childname} implicit variable that doesn't include the
fully qualified path would be useful for writing template profiles
for multiple nearly identical hats.]

Signed-off-by: Steve Beattie <steve at nxnw.org>
---
 parser/parser.h                                           |    4 
 parser/parser_symtab.c                                    |   63 ++++++++++++++
 parser/parser_variable.c                                  |   17 +++
 parser/profile.h                                          |   24 ++++-
 parser/tst/simple_tests/vars/vars_auto_profile_name_01.sd |    9 ++
 parser/tst/simple_tests/vars/vars_auto_profile_name_02.sd |    9 ++
 parser/tst/simple_tests/vars/vars_auto_profile_name_03.sd |    9 ++
 parser/tst/simple_tests/vars/vars_auto_profile_name_04.sd |   18 ++++
 parser/tst/simple_tests/vars/vars_auto_profile_name_05.sd |   40 ++++++++
 parser/tst/simple_tests/vars/vars_auto_profile_name_06.sd |   19 ++++
 parser/tst/simple_tests/vars/vars_auto_profile_name_07.sd |   22 ++++
 11 files changed, 226 insertions(+), 8 deletions(-)

Index: b/parser/parser_symtab.c
===================================================================
--- a/parser/parser_symtab.c
+++ b/parser/parser_symtab.c
@@ -330,6 +330,50 @@ char *get_next_set_value(struct set_valu
 	return ret;
 }
 
+/* delete_symbol
+ * removes an individual variable from the symbol table. We don't
+ * support this in the language, but for special variables that change
+ * between profiles, we need this.
+ */
+int delete_set_var(const char *var_name)
+{
+	int rc = 0;
+	struct symtab **result, *n, *var;
+
+	n = new_symtab_entry(var_name);
+	if (!n) {
+		rc = ENOMEM;
+		goto out;
+	}
+
+	result = (struct symtab **) tfind(n, &my_symtab, (comparison_fn_t) &compare_symtabs);
+	if (!result) {
+		/* XXX Warning? */
+		goto out;
+	}
+
+	var = (*result);
+
+	result = (struct symtab **) tdelete(n, &my_symtab, (comparison_fn_t) &compare_symtabs);
+	if (!result) {
+		PERROR("ASSERT: delete_set_var: tfind found var %s but tdelete failed to delete it\n",
+				var_name);
+		exit(1);
+	}
+
+	if (var->type != sd_set) {
+		PERROR("ASSERT: delete_set_var: deleting %s but is a boolean variable\n",
+				var_name);
+		exit(1);
+	}
+
+	free_symtab(var);
+
+out:
+	free_symtab(n);
+	return rc;
+}
+
 static void *seenlist = NULL;
 
 static int is_seen(const char *var)
@@ -708,6 +752,21 @@ int test_expand_set_var_during_dump(void
 	return rc;
 }
 
+int test_delete_set_var(void)
+{
+	int rc = 0;
+	int retval;
+
+	retval = new_set_var("deleteme", "delete this variable");
+	MY_TEST(retval == 0, "new delete set variable");
+	retval = delete_set_var("deleteme");
+	MY_TEST(retval == 0, "delete set variable");
+
+	free_symtabs();
+
+	return rc;
+}
+
 int main(void)
 {
 	int rc = 0;
@@ -740,6 +799,10 @@ int main(void)
 	if (rc == 0)
 		rc = retval;
 
+	retval = test_delete_set_var();
+	if (rc == 0)
+		rc = retval;
+
 	retval = new_set_var("test", "test value");
 	MY_TEST(retval == 0, "new set variable 1");
 
Index: b/parser/parser.h
===================================================================
--- a/parser/parser.h
+++ b/parser/parser.h
@@ -284,6 +284,9 @@ do {								\
 	version;					\
 })
 
+/* The parser fills this variable in automatically */
+#define PROFILE_NAME_VARIABLE "profile_name"
+
 /* from parser_common.c */
 extern uint32_t policy_version;
 extern uint32_t parser_abi_version;
@@ -404,6 +407,7 @@ extern int new_set_var(const char *var,
 extern int add_set_value(const char *var, const char *value);
 extern struct set_value *get_set_var(const char *var);
 extern char *get_next_set_value(struct set_value **context);
+extern int delete_set_var(const char *var_name);
 extern void dump_symtab(void);
 extern void dump_expanded_symtab(void);
 void free_symtabs(void);
Index: b/parser/parser_variable.c
===================================================================
--- a/parser/parser_variable.c
+++ b/parser/parser_variable.c
@@ -276,11 +276,22 @@ static int process_variables_in_rules(Pr
 
 int process_profile_variables(Profile *prof)
 {
-	int error = 0;
-       	error = process_variables_in_entries(prof->entries);
-       	if (!error)
+	int error = 0, rc;
+	std::string *buf = prof->get_name(true);
+
+	error = new_set_var(PROFILE_NAME_VARIABLE, buf->c_str());
+	delete buf;
+
+	if (!error)
+		error = process_variables_in_entries(prof->entries);
+
+	if (!error)
 		error = process_variables_in_rules(*prof);
 
+	rc = delete_set_var(PROFILE_NAME_VARIABLE);
+	if (!error)
+		error = rc;
+
 	return error;
 }
 
Index: b/parser/tst/simple_tests/vars/vars_auto_profile_name_01.sd
===================================================================
--- /dev/null
+++ b/parser/tst/simple_tests/vars/vars_auto_profile_name_01.sd
@@ -0,0 +1,9 @@
+#=DESCRIPTION reference auto profile_name variable in rules
+#=EXRESULT PASS
+
+/a/test/profile {
+  /a/test/profile rix,
+
+  /var/run/@{profile_name} rwk,
+
+}
Index: b/parser/tst/simple_tests/vars/vars_auto_profile_name_02.sd
===================================================================
--- /dev/null
+++ b/parser/tst/simple_tests/vars/vars_auto_profile_name_02.sd
@@ -0,0 +1,9 @@
+#=DESCRIPTION reference auto profile_name variable in rules
+#=EXRESULT PASS
+
+profile /a/test/profile {
+  /a/test/profile rix,
+
+  /var/@{profile_name}/tmp rwk,
+
+}
Index: b/parser/tst/simple_tests/vars/vars_auto_profile_name_03.sd
===================================================================
--- /dev/null
+++ b/parser/tst/simple_tests/vars/vars_auto_profile_name_03.sd
@@ -0,0 +1,9 @@
+#=DESCRIPTION reference auto profile_name variable in rules
+#=EXRESULT PASS
+
+profile this_is_a_test /a/test/profile {
+  /a/test/profile rix,
+
+  /run/@{profile_name}/tmp rwk,
+
+}
Index: b/parser/tst/simple_tests/vars/vars_auto_profile_name_04.sd
===================================================================
--- /dev/null
+++ b/parser/tst/simple_tests/vars/vars_auto_profile_name_04.sd
@@ -0,0 +1,18 @@
+#=DESCRIPTION reference auto profile_name variable in rules w/hats
+#=EXRESULT PASS
+
+/test/profile {
+  /test/profile rix,
+
+  /run/@{profile_name}/tmp rwk,
+
+  ^spork {
+    owner /tmp/* r,
+    /spork/@{profile_name}/** rw,
+  }
+
+  ^spelunkk {
+    owner /tmp/* r,
+    /spelunk/@{profile_name}/** rw,
+  }
+}
Index: b/parser/profile.h
===================================================================
--- a/parser/profile.h
+++ b/parser/profile.h
@@ -15,6 +15,8 @@
 #define __AA_PROFILE_H
 
 #include <set>
+#include <string>
+#include <iostream>
 
 #include "parser.h"
 #include "rule.h"
@@ -225,13 +227,25 @@ public:
 		hat_table.dump();
 	}
 
-	void dump_name(bool fqp)
+	std::string* get_name(bool fqp)
 	{
+		std::string *buf;
 		if (fqp && parent) {
-			parent->dump_name(fqp);
-			printf("//%s", name);
-		} else
-			printf("%s", name);
+			buf = parent->get_name(fqp);
+			buf->append("//");
+			buf->append(name);
+		} else {
+			return new std::string(name);
+		}
+
+		return buf;
+	}
+
+	void dump_name(bool fqp)
+	{
+		std::string *buf = get_name(fqp);;
+		cout << *buf;
+		delete buf;
 	}
 };
 
Index: b/parser/tst/simple_tests/vars/vars_auto_profile_name_05.sd
===================================================================
--- /dev/null
+++ b/parser/tst/simple_tests/vars/vars_auto_profile_name_05.sd
@@ -0,0 +1,40 @@
+#=DESCRIPTION reference auto profile_name variable in rules w/hats
+#=EXRESULT PASS
+
+profile idf3s2A6GX8vrk /simple/profile {
+  /test/profile rix,
+
+  /run/@{profile_name}/tmp rwk,
+
+  ^spork {
+    owner /tmp/* r,
+    /spork/@{profile_name}/** rw,
+  }
+
+  ^spelunkk {
+    owner /tmp/* r,
+    /spelunk/@{profile_name}/** rw,
+  }
+}
+
+profile LzdZb9bKTMN6y /not/simple/profile {
+  /test/profile rix,
+
+  /run/@{profile_name}/tmp rwk,
+
+  ^spork {
+    owner /tmp/* r,
+    /run/@{profile_name}/** rw,
+  }
+
+  ^spelunkk {
+    owner /tmp/* r,
+    /run/@{profile_name}/** rw,
+  }
+
+  ^spry {
+    owner /tmp/* r,
+    /run/@{profile_name}/** rw,
+  }
+
+}
Index: b/parser/tst/simple_tests/vars/vars_auto_profile_name_06.sd
===================================================================
--- /dev/null
+++ b/parser/tst/simple_tests/vars/vars_auto_profile_name_06.sd
@@ -0,0 +1,19 @@
+#=DESCRIPTION reference auto profile_name variable in rules w/Cx profiles
+#=EXRESULT PASS
+
+profile top_profile /test/profile {
+  /test/profile rix,
+
+  /run/@{profile_name}/tmp rwk,
+  /bin/spork Cx -> spork,
+
+  profile spork {
+    owner /tmp/* r,
+    /run/@{profile_name}/** rw,
+  }
+
+  profile spelunkk {
+    owner /tmp/* r,
+    /run/@{profile_name}/** rw,
+  }
+}
Index: b/parser/tst/simple_tests/vars/vars_auto_profile_name_07.sd
===================================================================
--- /dev/null
+++ b/parser/tst/simple_tests/vars/vars_auto_profile_name_07.sd
@@ -0,0 +1,22 @@
+#=DESCRIPTION ensure profile_name expansion after subprofiles works
+#=EXRESULT PASS
+
+profile top_profile /test/profile {
+  /test/profile rix,
+
+  /first/path/@{profile_name}/tmp rwk,
+  /bin/spork Cx -> spork,
+
+  profile spork {
+    owner /tmp/* r,
+    /run/@{profile_name}/** rw,
+  }
+
+  hat spelunkk {
+    owner /tmp/* r,
+    /run/@{profile_name}/** rw,
+  }
+
+  # Does this expand properly?
+  /second/path/@{profile_name}/tmp rk,
+}

-- 
Steve Beattie
<sbeattie at ubuntu.com>
http://NxNW.org/~steve/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <https://lists.ubuntu.com/archives/apparmor/attachments/20140328/79619e67/attachment-0001.pgp>


More information about the AppArmor mailing list