[apparmor] [patch] parser - add support for variable expansion in dbus rules v2

Steve Beattie steve at nxnw.org
Thu Aug 29 17:50:35 UTC 2013


Subject: parser - add support for variable expansion in dbus rules v2
Bug: https://bugs.launchpad.net/bugs/1218099

This patch adds support for expanding variables with dbus rules.
Specifically, they can expanded within the bus, name, path, member,
interface, and peer label fields.

Parser test cases and regression test cases are added as well.

Patch history:
  v1: initial version of patch
  v2: add equality.sh tests to verify that the results of using
      variable expansion is the same as what should be equivalent rules

Signed-off-by: Steve Beattie <sbeattie at ubuntu.com>
---
 parser/dbus.c                               |   24 ++++++++++++
 parser/dbus.h                               |    1 
 parser/parser_variable.c                    |   54 ++++++++++++++++++++++++++++
 parser/tst/equality.sh                      |   29 +++++++++++++++
 parser/tst/simple_tests/vars/vars_dbus_1.sd |   11 +++++
 parser/tst/simple_tests/vars/vars_dbus_2.sd |   11 +++++
 parser/tst/simple_tests/vars/vars_dbus_3.sd |   10 +++++
 parser/tst/simple_tests/vars/vars_dbus_4.sd |   13 ++++++
 parser/tst/simple_tests/vars/vars_dbus_5.sd |   12 ++++++
 parser/tst/simple_tests/vars/vars_dbus_6.sd |   11 +++++
 parser/tst/simple_tests/vars/vars_dbus_7.sd |   11 +++++
 tests/regression/apparmor/dbus.inc          |   11 +++++
 tests/regression/apparmor/dbus_message.sh   |   28 ++++++++++++++
 13 files changed, 226 insertions(+)

Index: b/parser/tst/simple_tests/vars/vars_dbus_1.sd
===================================================================
--- /dev/null
+++ b/parser/tst/simple_tests/vars/vars_dbus_1.sd
@@ -0,0 +1,11 @@
+#=DESCRIPTION reference variables in dbus rules
+#=EXRESULT PASS
+
+@{FOO}=bar baz
+@{BAR}=@{FOO} blort
+
+/does/not/exist {
+  dbus (send)
+       bus=session
+       path="/com/canonical/hud/applications/@{BAR}",
+}
Index: b/parser/parser_variable.c
===================================================================
--- a/parser/parser_variable.c
+++ b/parser/parser_variable.c
@@ -29,6 +29,7 @@
 
 #include "parser.h"
 #include "mount.h"
+#include "dbus.h"
 
 static inline char *get_var_end(char *var)
 {
@@ -213,6 +214,19 @@ int clone_and_chain_mnt(void *v)
 	return 1;
 }
 
+int clone_and_chain_dbus(void *v)
+{
+	struct dbus_entry *entry = v;
+
+	struct dbus_entry *dup = dup_dbus_entry(entry);
+	if (!dup)
+		return 0;
+
+	entry->next = dup;
+
+	return 1;
+}
+
 static int process_variables_in_entries(struct cod_entry *entry_list)
 {
 	int ret = TRUE, rc;
@@ -253,6 +267,42 @@ static int process_variables_in_mnt_entr
 	return ret;
 }
 
+static int process_dbus_variables(struct dbus_entry *entry_list)
+{
+	int ret = TRUE, rc;
+	struct dbus_entry *entry;
+
+	list_for_each(entry_list, entry) {
+		rc = expand_entry_variables(&entry->bus, entry,
+					    clone_and_chain_dbus);
+		if (!rc)
+			return FALSE;
+		rc = expand_entry_variables(&entry->name, entry,
+					    clone_and_chain_dbus);
+		if (!rc)
+			return FALSE;
+		rc = expand_entry_variables(&entry->peer_label, entry,
+					    clone_and_chain_dbus);
+		if (!rc)
+			return FALSE;
+		rc = expand_entry_variables(&entry->path, entry,
+					    clone_and_chain_dbus);
+		if (!rc)
+			return FALSE;
+		rc = expand_entry_variables(&entry->interface, entry,
+					    clone_and_chain_dbus);
+		if (!rc)
+			return FALSE;
+		rc = expand_entry_variables(&entry->member, entry,
+					    clone_and_chain_dbus);
+		if (!rc)
+			return FALSE;
+
+	}
+
+	return ret;
+}
+
 int process_variables(struct codomain *cod)
 {
 	int error = 0;
@@ -265,6 +315,10 @@ int process_variables(struct codomain *c
 		error = -1;
 	}
 
+	if (!process_dbus_variables(cod->dbus_ents)) {
+			error = -1;
+	}
+
 	if (process_hat_variables(cod) != 0) {
 			error = -1;
 	}
Index: b/parser/dbus.c
===================================================================
--- a/parser/dbus.c
+++ b/parser/dbus.c
@@ -141,6 +141,30 @@ out:
 	return ent;
 }
 
+#define DUP_STRING(orig, new, field) \
+	(new)->field = (orig)->field ? strdup((orig)->field) : NULL
+
+struct dbus_entry *dup_dbus_entry(struct dbus_entry *orig)
+{
+	struct dbus_entry *ent = NULL;
+	ent = (struct dbus_entry *) calloc(1, sizeof(struct dbus_entry));
+	if (!ent)
+		return NULL;
+
+	DUP_STRING(orig, ent, bus);
+	DUP_STRING(orig, ent, name);
+	DUP_STRING(orig, ent, peer_label);
+	DUP_STRING(orig, ent, path);
+	DUP_STRING(orig, ent, interface);
+	DUP_STRING(orig, ent, member);
+	ent->mode = orig->mode;
+	ent->audit = orig->audit;
+	ent->deny = orig->deny;
+
+	ent->next = orig->next;
+
+	return ent;
+}
 
 void print_dbus_entry(struct dbus_entry *ent)
 {
Index: b/parser/dbus.h
===================================================================
--- a/parser/dbus.h
+++ b/parser/dbus.h
@@ -43,6 +43,7 @@ struct dbus_entry {
 void free_dbus_entry(struct dbus_entry *ent);
 struct dbus_entry *new_dbus_entry(int mode, struct cond_entry *conds,
 				  struct cond_entry *peer_conds);
+struct dbus_entry *dup_dbus_entry(struct dbus_entry *ent);
 void print_dbus_entry(struct dbus_entry *ent);
 
 #endif /* __AA_DBUS_H */
Index: b/parser/tst/simple_tests/vars/vars_dbus_2.sd
===================================================================
--- /dev/null
+++ b/parser/tst/simple_tests/vars/vars_dbus_2.sd
@@ -0,0 +1,11 @@
+#=DESCRIPTION reference variables in dbus rules, interfaces
+#=EXRESULT PASS
+
+@{ORGS}=freedesktop ubuntu gnome kde
+
+/does/not/exist {
+  dbus (receive)
+       bus=accessibility
+       interface=org.@{ORGS}.DBus.Properties
+       path="/com/canonical/hud/applications/bar",
+}
Index: b/parser/tst/simple_tests/vars/vars_dbus_3.sd
===================================================================
--- /dev/null
+++ b/parser/tst/simple_tests/vars/vars_dbus_3.sd
@@ -0,0 +1,10 @@
+#=DESCRIPTION reference variables in dbus rules, bus fields
+#=EXRESULT PASS
+
+@{BUSES}=session system accessability choochoo
+
+/does/not/exist {
+  dbus (send)
+       bus=@{BUSES}
+       path="/com/canonical/hud/applications/baz",
+}
Index: b/parser/tst/simple_tests/vars/vars_dbus_4.sd
===================================================================
--- /dev/null
+++ b/parser/tst/simple_tests/vars/vars_dbus_4.sd
@@ -0,0 +1,13 @@
+#=DESCRIPTION reference variables in dbus rules, members
+#=EXRESULT PASS
+
+@{MEMBERS}=blurt blirt @{BAR}
+@{BAR}=@{FOO} blort
+@{FOO}=bink bank bonk blurry*
+
+/does/not/exist {
+  dbus (send)
+       bus=session
+       member=@{MEMBERS}
+       path="/com/canonical/hud/applications/biff",
+}
Index: b/parser/tst/simple_tests/vars/vars_dbus_5.sd
===================================================================
--- /dev/null
+++ b/parser/tst/simple_tests/vars/vars_dbus_5.sd
@@ -0,0 +1,12 @@
+#=DESCRIPTION reference variables in dbus rules, with peers
+#=EXRESULT PASS
+
+@{FOO}=bar baz
+@{BAR}=@{FOO} blort
+
+/does/not/exist {
+  dbus (send, receive)
+       bus=session
+       path="/foo/bar" member="bar"
+       peer=(name="com.@{FOO}" label="/usr/bin/app.@{FOO}"),
+}
Index: b/parser/tst/simple_tests/vars/vars_dbus_6.sd
===================================================================
--- /dev/null
+++ b/parser/tst/simple_tests/vars/vars_dbus_6.sd
@@ -0,0 +1,11 @@
+#=DESCRIPTION reference variables in dbus rules, with name
+#=EXRESULT PASS
+
+@{FOO}=bar baz
+@{BAR}=@{FOO} blort
+
+/does/not/exist {
+  dbus (bind)
+       bus=session
+       name="com.@{BAR}.@{FOO}",
+}
Index: b/parser/tst/simple_tests/vars/vars_dbus_7.sd
===================================================================
--- /dev/null
+++ b/parser/tst/simple_tests/vars/vars_dbus_7.sd
@@ -0,0 +1,11 @@
+#=DESCRIPTION reference variables in dbus rules, with duplicates
+#=EXRESULT PASS
+
+@{FOO}=bar baz bar
+@{BAR}=@{FOO} blort
+
+/does/not/exist {
+  dbus (bind)
+       bus=session
+       name="com.@{BAR}.@{FOO}",
+}
Index: b/tests/regression/apparmor/dbus.inc
===================================================================
--- a/tests/regression/apparmor/dbus.inc
+++ b/tests/regression/apparmor/dbus.inc
@@ -10,11 +10,22 @@
 gendbusprofile()
 {
 	genprofile --stdin <<EOF
+${__dbus_var_decl}
 $test {
   @{gen $test}
   $@
 }
 EOF
+	unset __dbus_var_decl
+}
+
+# the arguments passed are emitted in the profile's prologue, for
+# setting profile variables, e.g.
+#	set_dbus_var "@{MY_DBUS_VAR}=stuff"
+# the saved variable declaration gets unset after each test run
+set_dbus_var()
+{
+  __dbus_var_decl=$@
 }
 
 start_bus()
Index: b/tests/regression/apparmor/dbus_message.sh
===================================================================
--- a/tests/regression/apparmor/dbus_message.sh
+++ b/tests/regression/apparmor/dbus_message.sh
@@ -102,6 +102,34 @@ message_gendbusprofile "dbus send bus=se
 runtestfg "message (send allowed w/ bus, dest, path, interface, method)" pass $confined_args
 checktestfg "compare_logs $unconfined_log eq $confined_log"
 
+# Make sure send is allowed when confined with appropriate permissions along
+# with conditionals and variables (same tests as above, with vars)
+
+set_dbus_var "@{BUSES}=session system"
+message_gendbusprofile "dbus send bus=@{BUSES},"
+runtestfg "message (send allowed w/ bus)" pass $confined_args
+checktestfg "compare_logs $unconfined_log eq $confined_log"
+
+set_dbus_var "@{PEERNAMES}=com.ubuntu.what net.apparmor.wiki org.freedesktop.DBus"
+message_gendbusprofile "dbus send bus=session peer=(name=@{PEERNAMES}),"
+runtestfg "message (send allowed w/ bus, dest)" pass $confined_args
+checktestfg "compare_logs $unconfined_log eq $confined_log"
+
+set_dbus_var "@{PATHNAMES}=DBus spork spoon spork"
+message_gendbusprofile "dbus send bus=session path=/org/freedesktop/@{PATHNAMES} peer=(name=org.freedesktop.DBus),"
+runchecktest "message (send allowed w/ bus, dest, path)" pass $confined_args
+checktestfg "compare_logs $unconfined_log eq $confined_log"
+
+set_dbus_var "@{INTERFACE_NAMES}=DBus spork spoon spork"
+message_gendbusprofile "dbus send bus=session path=/org/freedesktop/DBus interface=org.freedesktop.@{INTERFACE_NAMES} peer=(name=org.freedesktop.DBus),"
+runtestfg "message (send allowed w/ bus, dest, path, interface)" pass $confined_args
+checktestfg "compare_logs $unconfined_log eq $confined_log"
+
+set_dbus_var "@{MEMBERS}=Hello ListNames Spork Spoon"
+message_gendbusprofile "dbus send bus=session path=/org/freedesktop/DBus interface=org.freedesktop.DBus member=@{MEMBERS} peer=(name=org.freedesktop.DBus),"
+runtestfg "message (send allowed w/ bus, dest, path, interface, method)" pass $confined_args
+checktestfg "compare_logs $unconfined_log eq $confined_log"
+
 # Make sure send is denied when confined with appropriate permissions along
 # with incorrect conditionals
 
Index: b/parser/tst/equality.sh
===================================================================
--- a/parser/tst/equality.sh
+++ b/parser/tst/equality.sh
@@ -148,6 +148,35 @@ verify_binary_equality "dbus access pars
 	"/t { dbus (send,receive,,,,,,,,,,,,,,,,bind), }" \
 	"/t { dbus (send,send,send,send send receive,bind), }" \
 
+verify_binary_equality "dbus variable expansion" \
+	"/t { dbus (send, receive) path=/com/foo member=spork interface=org.foo peer=(name=com.foo label=/com/foo), }" \
+	"@{FOO}=foo
+	    /t { dbus (send, receive) path=/com/@{FOO} member=spork interface=org.@{FOO} peer=(name=com.@{FOO} label=/com/@{FOO}), }" \
+	"@{FOO}=foo
+	 @{SPORK}=spork
+	    /t { dbus (send, receive) path=/com/@{FOO} member=@{SPORK} interface=org.@{FOO} peer=(name=com.@{FOO} label=/com/@{FOO}), }" \
+	"@{FOO}=/com/foo
+            /t { dbus (send, receive) path=@{FOO} member=spork interface=org.foo peer=(name=com.foo label=@{FOO}), }" \
+	"@{FOO}=com
+            /t { dbus (send, receive) path=/@{FOO}/foo member=spork interface=org.foo peer=(name=@{FOO}.foo label=/@{FOO}/foo), }"
+
+verify_binary_equality "dbus variable expansion, multiple values/rules" \
+	"/t { dbus (send, receive) path=/com/foo, dbus (send, receive) path=/com/bar, }" \
+	"@{FOO}=foo
+	    /t { dbus (send, receive) path=/com/@{FOO}, dbus (send, receive) path=/com/bar, }" \
+	"@{FOO}=foo bar
+	    /t { dbus (send, receive) path=/com/@{FOO}, }" \
+	"@{FOO}=bar foo
+	    /t { dbus (send, receive) path=/com/@{FOO}, }"
+
+verify_binary_equality "dbus variable expansion, ensure rule de-duping occurs" \
+	"/t { dbus (send, receive) path=/com/foo, dbus (send, receive) path=/com/bar, }" \
+	"/t { dbus (send, receive) path=/com/foo, dbus (send, receive) path=/com/bar, dbus (send, receive) path=/com/bar, }" \
+	"@{FOO}=bar foo bar foo
+	    /t { dbus (send, receive) path=/com/@{FOO}, }" \
+	"@{FOO}=bar foo bar foo
+	    /t { dbus (send, receive) path=/com/@{FOO}, dbus (send, receive) path=/com/@{FOO}, }"
+
 if [ $fails -ne 0 -o $errors -ne 0 ]
 then
 	printf "ERRORS: %d\nFAILS: %d\n" $errors $fails 2>&1

-- 
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: 836 bytes
Desc: Digital signature
URL: <https://lists.ubuntu.com/archives/apparmor/attachments/20130829/d53a9448/attachment-0001.pgp>


More information about the AppArmor mailing list