On Wed, Mar 05, 2014 at 05:44:44PM -0800, Steve Beattie wrote: > This patch adds very limited support for very dumb parsing of dbus > rules. Basically, it stores dbus rules as raw strings wrapped in > a class. > > There's class structure to indicate how I'd like to see fuller future > support for dbus rules to be implemented and act as a guidepost for > how to handle most rules, moving away from the giant structure of > nested dictionaries. A stub test script is included as well, with a > modification to the make check target to set the PYTHONPATH to point > in the right place. > > With this patch, aa-audit, aa-autodep, aa-complain, aa-disable, > and aa-enforce all function for me. aa-logprof and aa-genprof have > functionality issues for me at the moment (one of them dumps a > backtrace even without this patch), and I'm not sure the writing out > of dbus rules is completely implemented for modified profiles. > > Signed-off-by: Steve Beattie <[email protected]>
Nice! Acked-by: Seth Arnold <[email protected]> > --- > utils/apparmor/aa.py | 64 > ++++++++++++++++++++++++++++++++++++++++++ > utils/apparmor/rules.py | 57 +++++++++++++++++++++++++++++++++++++ > utils/test/Makefile | 2 - > utils/test/test-dbus_parse.py | 30 +++++++++++++++++++ > 4 files changed, 152 insertions(+), 1 deletion(-) > > Index: b/utils/apparmor/aa.py > =================================================================== > --- a/utils/apparmor/aa.py > +++ b/utils/apparmor/aa.py > @@ -39,6 +39,8 @@ from apparmor.aamode import (str_to_mode > mode_to_str_user, mode_contains, AA_OTHER, > flatten_mode, owner_flatten_mode) > > +import apparmor.rules as aarules > + > from apparmor.yasti import SendDataToYast, GetDataFromYast, shutdown_yast > > # setup module translations > @@ -2613,6 +2615,7 @@ RE_PROFILE_CHANGE_HAT = re.compile('^\s* > RE_PROFILE_HAT_DEF = > re.compile('^\s*\^(\"??.+?\"??)\s+((flags=)?\((.+)\)\s+)*\{\s*(#.*)?$') > RE_NETWORK_FAMILY_TYPE = re.compile('\s+(\S+)\s+(\S+)\s*,$') > RE_NETWORK_FAMILY = re.compile('\s+(\S+)\s*,$') > +RE_PROFILE_DBUS = > re.compile('^\s*(audit\s+)?(allow\s+|deny\s+)?(dbus[^#]*)\s*(#.*)?$') > > def parse_profile_data(data, file, do_include): > profile_data = hasher() > @@ -2676,6 +2679,7 @@ def parse_profile_data(data, file, do_in > > profile_data[profile][hat]['allow']['netdomain'] = hasher() > profile_data[profile][hat]['allow']['path'] = hasher() > + profile_data[profile][hat]['allow']['dbus'] = list() > # Save the initial comment > if initial_comment: > profile_data[profile][hat]['initial_comment'] = > initial_comment > @@ -2926,6 +2930,29 @@ def parse_profile_data(data, file, do_in > > profile_data[profile][hat][allow]['netdomain']['rule']['all'] = True > > profile_data[profile][hat][allow]['netdomain']['audit']['all'] = audit # True > > + elif RE_PROFILE_DBUS.search(line): > + matches = RE_PROFILE_DBUS.search(line).groups() > + > + if not profile: > + raise AppArmorException(_('Syntax Error: Unexpected dbus > entry found in file: %s line: %s') % (file, lineno + 1)) > + > + audit = False > + if matches[0]: > + audit = True > + allow = 'allow' > + if matches[1] and matches[1].strip() == 'deny': > + allow = 'deny' > + dbus = matches[2] > + > + #parse_dbus_rule(profile_data[profile], dbus, audit, allow) > + dbus_rule = parse_dbus_rule(dbus) > + dbus_rule.audit = audit > + dbus_rule.deny = (allow == 'deny') > + > + dbus_rules = profile_data[profile][hat][allow].get('dbus', > list()) > + dbus_rules.append(dbus_rule) > + profile_data[profile][hat][allow]['dbus'] = dbus_rules > + > elif RE_PROFILE_CHANGE_HAT.search(line): > matches = RE_PROFILE_CHANGE_HAT.search(line).groups() > > @@ -2998,6 +3025,21 @@ def parse_profile_data(data, file, do_in > > return profile_data > > +# RE_DBUS_ENTRY = re.compile('^dbus\s*()?,\s*$') > +# use stuff like '(?P<action>(send|write|w|receive|read|r|rw))' > + > +def parse_dbus_rule(line): > + # XXX Do real parsing here > + return aarules.Raw_DBUS_Rule(line) > + > + #matches = RE_DBUS_ENTRY.search(line).groups() > + #if len(matches) == 1: > + # XXX warn? > + # matched nothing > + # print('no matches') > + # return aarules.DBUS_Rule() > + #print(line) > + > def separate_vars(vs): > """Returns a list of all the values for a variable""" > data = [] > @@ -3188,6 +3230,24 @@ def write_netdomain(prof_data, depth): > data += write_net_rules(prof_data, depth, 'allow') > return data > > +def write_dbus_rules(prof_data, depth, allow): > + pre = ' ' * depth > + data = [] > + > + # no dbus rules, so return > + if not prof_data[allow].get('dbus', False): > + return data > + > + for dbus_rule in prof_data[allow]['dbus']: > + data.append('%s%s' % (pre, dbus_rule.serialize())) > + data.append('') > + return data > + > +def write_dbus(prof_data, depth): > + data = write_dbus_rules(prof_data, depth, 'deny') > + data += write_net_rules(prof_data, depth, 'allow') > + return data > + > def write_link_rules(prof_data, depth, allow): > pre = ' ' * depth > data = [] > @@ -3280,6 +3340,7 @@ def write_rules(prof_data, depth): > data += write_rlimits(prof_data, depth) > data += write_capabilities(prof_data, depth) > data += write_netdomain(prof_data, depth) > + data += write_dbus(prof_data, depth) > data += write_links(prof_data, depth) > data += write_paths(prof_data, depth) > data += write_change_profile(prof_data, depth) > @@ -3427,6 +3488,7 @@ def serialize_profile_from_old_profile(p > 'rlimit': write_rlimits, > 'capability': write_capabilities, > 'netdomain': write_netdomain, > + 'dbus': write_dbus, > 'link': write_links, > 'path': write_paths, > 'change_profile': write_change_profile, > @@ -3438,6 +3500,7 @@ def serialize_profile_from_old_profile(p > 'rlimit': False, > 'capability': False, > 'netdomain': False, > + 'dbus': False, > 'link': False, > 'path': False, > 'change_profile': False, > @@ -3516,6 +3579,7 @@ def serialize_profile_from_old_profile(p > data += write_rlimits(write_prof_data, depth) > data += write_capabilities(write_prof_data[name], depth) > data += write_netdomain(write_prof_data[name], depth) > + data += write_dbus(write_prof_data[name], depth) > data += write_links(write_prof_data[name], depth) > data += write_paths(write_prof_data[name], depth) > data += write_change_profile(write_prof_data[name], > depth) > Index: b/utils/apparmor/rules.py > =================================================================== > --- /dev/null > +++ b/utils/apparmor/rules.py > @@ -0,0 +1,57 @@ > +# ------------------------------------------------------------------ > +# > +# Copyright (C) 2014 Canonical Ltd. > +# > +# This program is free software; you can redistribute it and/or > +# modify it under the terms of version 2 of the GNU General Public > +# License published by the Free Software Foundation. > +# > +# ------------------------------------------------------------------ > + > +class DBUS_Rule(object): > + actions = set() > + busses = set() > + names = set() > + paths = set() > + interfaces = set() > + members = set() > + peer_names = set() > + peer_labels = set() > + > + audit = False > + deny = False > + > + def __init__(self, actions=[], busses=[], names=[], paths=[], > interfaces=[], > + members=[], peer_names=[], peer_labels=[]): > + self.actions = set(actions) > + self.busses = set(busses) > + self.names = set(names) > + self.paths = set(paths) > + self.interfaces = set(interfaces) > + self.members = set(members) > + self.peer_name = set(peer_names) > + self.peer_labels = set(peer_labels) > + > + def serialize(self): > + out = "%s%s%s" % ('audit ' if self.audit else '', > + 'deny ' if self.deny else '', > + 'dbus') > + if len(self.actions) > 0: > + if len(self.actions) == 1: > + out += ' %s' % self.actions[0] > + else: > + out += ' (%s)' % (', '.join(self.actions)) > + out += ',' > + return out > + > +class Raw_DBUS_Rule(object): > + audit = False > + deny = False > + > + def __init__(self, rule): > + self.rule = rule > + > + def serialize(self): > + return "%s%s%s" % ('audit ' if self.audit else '', > + 'deny ' if self.deny else '', > + self.rule) > Index: b/utils/test/test-dbus_parse.py > =================================================================== > --- /dev/null > +++ b/utils/test/test-dbus_parse.py > @@ -0,0 +1,30 @@ > +#! /usr/bin/env python > +# ------------------------------------------------------------------ > +# > +# Copyright (C) 2014 Canonical Ltd. > +# > +# This program is free software; you can redistribute it and/or > +# modify it under the terms of version 2 of the GNU General Public > +# License published by the Free Software Foundation. > +# > +# ------------------------------------------------------------------ > + > +import apparmor.aa as aa > +import unittest > + > +class AAParseDBUSTest(unittest.TestCase): > + > + def test_parse_plain_dbus_rule(self): > + dstring = 'dbus,' > + dbus = aa.parse_dbus_rule(dstring) > + self.assertEqual(dstring, dbus.serialize(), > + 'dbus object returned "%s", expected "%s"' % > (dbus.serialize(), dstring)) > + > + def test_parse_dbus_simple_send_rule(self): > + dstring = 'dbus send,' > + dbus = aa.parse_dbus_rule(dstring) > + self.assertEqual(dstring, dbus.serialize(), > + 'dbus object returned "%s", expected "%s"' % > (dbus.serialize(), dstring)) > + > +if __name__ == '__main__': > + unittest.main() > Index: b/utils/test/Makefile > =================================================================== > --- a/utils/test/Makefile > +++ b/utils/test/Makefile > @@ -38,4 +38,4 @@ ifndef VERBOSE > .SILENT: check > endif > check: > - $(foreach test, $(wildcard test-*.py), $(call pyalldo, $(test))) > + export PYTHONPATH=.. ; $(foreach test, $(wildcard test-*.py), $(call > pyalldo, $(test))) > > > -- > AppArmor mailing list > [email protected] > Modify settings or unsubscribe at: > https://lists.ubuntu.com/mailman/listinfo/apparmor >
signature.asc
Description: Digital signature
-- AppArmor mailing list [email protected] Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor
