[apparmor] [patch 1/3] Add NetworkRule and NetworkRuleset classes
Kshitij Gupta
kgupta8592 at gmail.com
Wed Apr 15 17:29:09 UTC 2015
Hello,
On Wed, Apr 15, 2015 at 3:07 AM, Christian Boltz <apparmor at cboltz.de> wrote:
> Hello,
>
> this patch adds utils/apparmor/rule/network.py with the NetworkRule and
> NetworkRuleset classes. These classes are meant to handle network rules.
>
> In comparison to the existing code in aa.py, relevant news are:
> - the keywords are checked against a list of allowed domains, types and
> protocols (these lists are based on what the utils/vim/Makefile
> generates - on the long term an autogenerated file with the keywords
> for all rule types would be nice ;-)
>
In theory you can have a script generate a python module that solely
contains these keywords, which can be imported in here. Sounds pretty
trivial ;-)
> - there are variables for domain and type_or_protocol instead of
> first_param and second_param. (If someone is bored enough to map the
> protocol "shortcuts" to their expanded meaning, that shouldn't be too
> hard.)
> - (obviously) more readable code because we have everything at one place
> now
>
yay!
> - some bugs are fixed along the way (for example, "network foo" will now
> be kept, not "network foo bar" - see my last mail about
> write_net_rules() for details)
>
>
>
> [ 44-add-NetworkRule-and-NetworkRuleset-classes.diff ]
>
> === added file 'utils/apparmor/rule/network.py'
> --- utils/apparmor/rule/network.py 1970-01-01 00:00:00 +0000
> +++ utils/apparmor/rule/network.py 2015-04-14 20:47:40 +0000
> @@ -0,0 +1,210 @@
> +#!/usr/bin/env python
> +# ----------------------------------------------------------------------
> +# Copyright (C) 2013 Kshitij Gupta <kgupta8592 at gmail.com>
> +# Copyright (C) 2015 Christian Boltz <apparmor at cboltz.de>
> +#
> +# 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 as published by the Free Software Foundation.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# ----------------------------------------------------------------------
> +
> +import re
> +
> +from apparmor.regex import RE_PROFILE_NETWORK
> +from apparmor.common import AppArmorBug, AppArmorException
> +from apparmor.rule import BaseRule, BaseRuleset, parse_modifiers
> +
> +# setup module translations
> +from apparmor.translations import init_translation
> +_ = init_translation()
> +
> +
> +network_domain_keywords = [ 'unix', 'inet', 'ax25', 'ipx', 'appletalk',
> 'netrom', 'bridge', 'atmpvc', 'x25', 'inet6',
> + 'rose', 'netbeui', 'security', 'key',
> 'netlink', 'packet', 'ash', 'econet', 'atmsvc', 'rds', 'sna',
> + 'irda', 'pppox', 'wanpipe', 'llc', 'can',
> 'tipc', 'bluetooth', 'iucv', 'rxrpc', 'isdn', 'phonet',
> + 'ieee802154', 'caif', 'alg', 'nfc', 'vsock'
> ]
> + # missing in manpage: 'unix', 'rds', 'llc', 'can', 'tipc',
> 'iucv', 'rxrpc', 'isdn', 'phonet', 'ieee802154', 'caif', 'alg', 'nfc',
> 'vsock'
> +
>
comments from others on the missing types?
+network_type_keywords = ['stream', 'dgram', 'seqpacket', 'rdm', 'raw',
> 'packet']
> +network_protocol_keywords = ['tcp', 'udp', 'icmp']
> +
> +
> +RE_NETWORK_DOMAIN = '(' + '|'.join(network_domain_keywords) + ')'
> +RE_NETWORK_TYPE = '(' + '|'.join(network_type_keywords) + ')'
> +RE_NETWORK_PROTOCOL = '(' + '|'.join(network_protocol_keywords) + ')'
>
neat!
> +
> +RE_NETWORK_DETAILS = re.compile(
> + '^\s*(' +
> + '(?P<domain>' + RE_NETWORK_DOMAIN + ')(\s+(?P<type_or_protocol>'
> + RE_NETWORK_TYPE + '|' + RE_NETWORK_PROTOCOL + '))?' + # domain, optional
> type or protocol
>
exercising new/larger monitor privileges? ;-)
can be split into two lines I think.
+ '|' + # or
> + '(?P<protocol>' + RE_NETWORK_PROTOCOL + ')' + # protocol only
> + ')\s*$')
>
The leading and trailing \s* become superfluous as __parse has:
rule_details = matches.group('details').strip()
+
+
> +
> +
> +
> +
> +
>
what is the standard for whitespace separation? 7 seems a bit much.
+class NetworkRule(BaseRule):
> + '''Class to handle and store a single network rule'''
> +
> + # Nothing external should reference this class, all external users
> + # should reference the class field NetworkRule.ALL
> + class __NetworkAll(object):
> + pass
> +
>
+ ALL = __NetworkAll
> +
> + def __init__(self, domain, type_or_protocol, audit=False, deny=False,
> allow_keyword=False,
> + comment='', log_event=None):
> +
> + '''
> + NETWORK RULE = 'network' [ [ DOMAIN [ TYPE | PROTOCOL ] ] | [
> PROTOCOL ] ] ','
> + '''
> +
> + super(NetworkRule, self).__init__(audit=audit, deny=deny,
> + allow_keyword=allow_keyword,
> + comment=comment,
> + log_event=log_event)
> +
> + self.domain = None
> + self.all_domains = False
> + if domain == NetworkRule.ALL:
> + self.all_domains = True
> + elif type(domain) == str:
> + if domain in network_domain_keywords:
> + self.domain = domain
> + else:
> + raise AppArmorBug('Passed unknown domain to NetworkRule:
> %s' % str(domain))
>
str(domain) is unnecessary, as type of domain is known to be str.
> + else:
> + raise AppArmorBug('Passed unknown object to NetworkRule: %s'
> % str(domain))
> +
> + self.type_or_protocol = None
> + self.all_type_or_protocols = False
> + if type_or_protocol == NetworkRule.ALL:
> + self.all_type_or_protocols = True
> + elif type(type_or_protocol) == str:
> + if type_or_protocol in network_protocol_keywords:
> + self.type_or_protocol = type_or_protocol
> + elif type_or_protocol in network_type_keywords:
> + if self.all_domains:
> + raise AppArmorException('Passing type %s to
> NetworkRule without specifying a domain keyword is not allowed' %
> str(type_or_protocol))
>
str(type_or_protocol) not required.
+ self.type_or_protocol = type_or_protocol
> + else:
> + raise AppArmorBug('Passed unknown type_or_protocol to
> NetworkRule: %s' % str(type_or_protocol))
>
str(type_or_protocol) not required. #copy paste reviews
+ else:
> + raise AppArmorBug('Passed unknown object to NetworkRule: %s'
> % str(type_or_protocol))
> +
> + @classmethod
> + def _parse(cls, raw_rule):
> + '''parse raw_rule and return NetworkRule'''
> +
> + matches = RE_PROFILE_NETWORK.search(raw_rule)
> + if not matches:
> + raise AppArmorException(_("Invalid network rule '%s'") %
> raw_rule)
> +
> + audit, deny, allow_keyword, comment = parse_modifiers(matches)
> +
> + rule_details = ''
> + if matches.group('details'):
> + rule_details = matches.group('details').strip()
> +
> + if rule_details:
> + details = RE_NETWORK_DETAILS.search(rule_details)
> + if not details:
> + raise AppArmorException(_("Invalid or unknown keywords in
> 'network %s" % rule_details))
> +
> + if details.group('domain'):
> + domain = details.group('domain')
> + else:
> + domain = NetworkRule.ALL
> +
> + if details.group('type_or_protocol'):
> + type_or_protocol = details.group('type_or_protocol')
> + elif details.group('protocol'):
> + type_or_protocol = details.group('protocol')
> + else:
> + type_or_protocol = NetworkRule.ALL
> + else:
> + domain = NetworkRule.ALL
> + type_or_protocol = NetworkRule.ALL
> +
> + return NetworkRule(domain, type_or_protocol,
> + audit=audit, deny=deny,
> allow_keyword=allow_keyword, comment=comment)
> +
> + def get_clean(self, depth=0):
> + '''return rule (in clean/default formatting)'''
> +
> + space = ' ' * depth
> +
> + if self.all_domains:
> + domain = ''
> + elif self.domain:
> + domain = ' %s' % self.domain
> + else:
> + raise AppArmorBug('Empty domain in network rule')
> +
> + if self.all_type_or_protocols:
> + type_or_protocol = ''
> + elif self.type_or_protocol:
> + type_or_protocol = ' %s' % self.type_or_protocol
> + else:
> + raise AppArmorBug('Empty type or protocol in network rule')
> +
> + return('%s%snetwork%s%s,%s' % (space, self.modifiers_str(),
> domain, type_or_protocol, self.comment))
> +
> + def is_covered_localvars(self, other_rule):
> + '''check if other_rule is covered by this rule object'''
> +
> + if not other_rule.domain and not other_rule.all_domains:
> + raise AppArmorBug('No domain specified in other network rule')
> +
> + if not other_rule.type_or_protocol and not
> other_rule.all_type_or_protocols:
> + raise AppArmorBug('No type or protocol specified in other
> network rule')
> +
> + if not self.all_domains:
> + if other_rule.all_domains:
> + return False
> + if other_rule.domain != self.domain:
> + return False
> +
> + if not self.all_type_or_protocols:
> + if other_rule.all_type_or_protocols:
> + return False
> + if other_rule.type_or_protocol != self.type_or_protocol:
> + return False
> +
> + # still here? -> then it is covered
> + return True
> +
> + def is_equal_localvars(self, rule_obj):
> + '''compare if rule-specific variables are equal'''
> +
> + if not type(rule_obj) == NetworkRule:
> + raise AppArmorBug('Passes non-network rule: %s' %
> str(rule_obj))
>
Passes or Passed?
+
> + if (self.domain != rule_obj.domain
> + or self.all_domains != rule_obj.all_domains):
> + return False
> +
> + if (self.type_or_protocol != rule_obj.type_or_protocol
> + or self.all_type_or_protocols !=
> rule_obj.all_type_or_protocols):
> + return False
> +
> + return True
> +
> +
> +class NetworkRuleset(BaseRuleset):
> + '''Class to handle and store a collection of network rules'''
> +
> + def get_glob(self, path_or_rule):
> + '''Return the next possible glob. For network rules, that's
> "network DOMAIN," or "network," (all network)'''
> + # XXX return 'network DOMAIN,'
> + return 'network,'
>
>
>
> Thanks.
Regards,
Kshitij Gupta
> Regards,
>
> Christian Boltz
> --
> We break the translation consistently (wow, consistent break, I like
> that wording) [from https://bugzilla.novell.com/show_bug.cgi?id=165509]
>
>
> --
> AppArmor mailing list
> AppArmor at lists.ubuntu.com
> Modify settings or unsubscribe at:
> https://lists.ubuntu.com/mailman/listinfo/apparmor
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ubuntu.com/archives/apparmor/attachments/20150415/2f9317c0/attachment-0001.html>
More information about the AppArmor
mailing list