parser - add support for variable expansion in dbus rules

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@ubuntu.com>
Acked-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Seth Arnold <seth.arnold@canonical.com>
This commit is contained in:
Steve Beattie 2013-08-29 12:34:13 -07:00
parent 2420c573d0
commit 05029cb9b7
13 changed files with 226 additions and 0 deletions

View file

@ -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)
{

View file

@ -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 */

View file

@ -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_entries(struct mnt_entry *entry_list)
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 *cod)
error = -1;
}
if (!process_dbus_variables(cod->dbus_ents)) {
error = -1;
}
if (process_hat_variables(cod) != 0) {
error = -1;
}

View file

@ -148,6 +148,35 @@ verify_binary_equality "dbus access parsing" \
"/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

View file

@ -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}",
}

View file

@ -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",
}

View file

@ -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",
}

View file

@ -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",
}

View file

@ -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}"),
}

View file

@ -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}",
}

View file

@ -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}",
}

View file

@ -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()

View file

@ -102,6 +102,34 @@ message_gendbusprofile "dbus send bus=session path=/org/freedesktop/DBus interfa
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