def __setitem__(self, key, value): if key not in self.data: raise AppArmorBug('attempt to set unknown key %s' % key) # allow writing bool values if type(self.data[key]) == bool: if type(value) == bool: self.data[key] = value else: raise AppArmorBug( 'Attempt to change type of "%s" from %s to %s, value %s' % (key, type(self.data[key]), type(value), value)) # allow writing str or None to some keys elif key in ('xattrs', 'flags', 'filename'): if type_is_str(value) or value is None: self.data[key] = value else: raise AppArmorBug( 'Attempt to change type of "%s" from %s to %s, value %s' % (key, type(self.data[key]), type(value), value)) # allow writing str values elif type_is_str(self.data[key]): if type_is_str(value): self.data[key] = value else: raise AppArmorBug( 'Attempt to change type of "%s" from %s to %s, value %s' % (key, type(self.data[key]), type(value), value)) # don't allow overwriting of other types else: raise AppArmorBug('Attempt to overwrite "%s" with %s, type %s' % (key, value, type(value)))
def __init__(self, rlimit, value, audit=False, deny=False, allow_keyword=False, comment='', log_event=None): super(RlimitRule, self).__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, log_event=log_event) if audit or deny or allow_keyword: raise AppArmorBug('The audit, allow or deny keywords are not allowed in rlimit rules.') if type_is_str(rlimit): if rlimit in rlimit_all: self.rlimit = rlimit else: raise AppArmorException('Unknown rlimit keyword in rlimit rule: %s' % rlimit) else: raise AppArmorBug('Passed unknown object to RlimitRule: %s' % str(rlimit)) self.value = None self.value_as_int = None self.all_values = False if value == RlimitRule.ALL: self.all_values = True elif type_is_str(value): if not value.strip(): raise AppArmorBug('Empty value in rlimit rule') elif rlimit in rlimit_size: if not RE_UNIT_SIZE.match(value): raise AppArmorException('Invalid value or unit in rlimit %s %s rule' % (rlimit, value)) self.value_as_int = self.size_to_int(value) elif rlimit in rlimit_number: if not RE_NUMBER.match(value): raise AppArmorException('Invalid value in rlimit %s %s rule' % (rlimit, value)) self.value_as_int = int(value) elif rlimit in rlimit_time: if not RE_NUMBER_UNIT.match(value): raise AppArmorException('Invalid value in rlimit %s %s rule' % (rlimit, value)) number, unit = split_unit(value) if rlimit == 'rttime': self.value_as_int = self.time_to_int(value, 'us') else: self.value_as_int = self.time_to_int(value, 'seconds') elif rlimit in rlimit_nice: if not RE_NICE.match(value): raise AppArmorException('Invalid value or unit in rlimit %s %s rule' % (rlimit, value)) self.value_as_int = 0 - int(value) # lower numbers mean a higher limit for nice # still here? fine :-) self.value = value else: raise AppArmorBug('Passed unknown object to RlimitRule: %s' % str(value))
def __init__(self, rlimit, value, audit=False, deny=False, allow_keyword=False, comment='', log_event=None): super(RlimitRule, self).__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, log_event=log_event) if audit or deny or allow_keyword: raise AppArmorBug('The audit, allow or deny keywords are not allowed in rlimit rules.') if type_is_str(rlimit): if rlimit in rlimit_all: self.rlimit = rlimit else: raise AppArmorException('Unknown rlimit keyword in rlimit rule: %s' % rlimit) else: raise AppArmorBug('Passed unknown object to RlimitRule: %s' % str(rlimit)) self.value = None self.value_as_int = None self.all_values = False if value == RlimitRule.ALL: self.all_values = True elif type_is_str(value): if not value.strip(): raise AppArmorBug('Empty value in rlimit rule') elif rlimit in rlimit_size: if not RE_UNIT_SIZE.match(value): raise AppArmorException('Invalid value or unit in rlimit %s %s rule' % (rlimit, value)) self.value_as_int = self.size_to_int(value) elif rlimit in rlimit_number: if not RE_NUMBER.match(value): raise AppArmorException('Invalid value in rlimit %s %s rule' % (rlimit, value)) self.value_as_int = int(value) elif rlimit in rlimit_time: if not RE_NUMBER_UNIT.match(value): raise AppArmorException('Invalid value in rlimit %s %s rule' % (rlimit, value)) number, unit = split_unit(value) if rlimit == 'rttime': self.value_as_int = self.time_to_int(value, 'us') else: self.value_as_int = self.time_to_int(value, 'seconds') elif rlimit in rlimit_nice: # pragma: no branch - "if rlimit in rlimit_all:" above avoids the need for an "else:" branch if not RE_NICE.match(value): raise AppArmorException('Invalid value or unit in rlimit %s %s rule' % (rlimit, value)) self.value_as_int = 0 - int(value) # lower numbers mean a higher limit for nice # still here? fine :-) self.value = value else: raise AppArmorBug('Passed unknown object to RlimitRule: %s' % str(value))
def __init__(self, varname, mode, values, audit=False, deny=False, allow_keyword=False, comment='', log_event=None): super(VariableRule, self).__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, log_event=log_event) # variables don't support audit or deny if audit: raise AppArmorBug('Attempt to initialize %s with audit flag' % self.__class__.__name__) if deny: raise AppArmorBug('Attempt to initialize %s with deny flag' % self.__class__.__name__) if not type_is_str(varname): raise AppArmorBug('Passed unknown type for varname to %s: %s' % (self.__class__.__name__, varname)) if not varname.startswith('@{'): raise AppArmorException( "Passed invalid varname to %s (doesn't start with '@{'): %s" % (self.__class__.__name__, varname)) if not varname.endswith('}'): raise AppArmorException( "Passed invalid varname to %s (doesn't end with '}'): %s" % (self.__class__.__name__, varname)) if not type_is_str(mode): raise AppArmorBug( 'Passed unknown type for variable assignment mode to %s: %s' % (self.__class__.__name__, mode)) if mode not in ['=', '+=']: raise AppArmorBug( 'Passed unknown variable assignment mode to %s: %s' % (self.__class__.__name__, mode)) if type(values) is not set: raise AppArmorBug('Passed unknown type for values to %s: %s' % (self.__class__.__name__, values)) if not values: raise AppArmorException('Passed empty list of values to %s: %s' % (self.__class__.__name__, values)) self.varname = varname self.mode = mode self.values = values
def __init__(self, cap_list, audit=False, deny=False, allow_keyword=False, comment='', log_event=None): super(CapabilityRule, self).__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, log_event=log_event) # Because we support having multiple caps in one rule, # initializer needs to accept a list of caps. self.all_caps = False if cap_list == CapabilityRule.ALL: self.all_caps = True self.capability = set() else: if type_is_str(cap_list): self.capability = {cap_list} elif type(cap_list) == list and len(cap_list) > 0: self.capability = set(cap_list) else: raise AppArmorBug( 'Passed unknown object to CapabilityRule: %s' % str(cap_list)) # make sure none of the cap_list arguments are blank, in # case we decide to return one cap per output line for cap in self.capability: if len(cap.strip()) == 0: raise AppArmorBug( 'Passed empty capability to CapabilityRule: %s' % str(cap_list))
def _aare_or_all(self, rulepart, partname, is_path, log_event): '''checks rulepart and returns - (AARE, False) if rulepart is a (non-empty) string - (None, True) if rulepart is all_obj (typically *Rule.ALL) - raises AppArmorBug if rulepart is an empty string or has a wrong type Parameters: - rulepart: the rule part to check (string or *Rule.ALL object) - partname: the name of the rulepart (for example 'peer', used for exception messages) - is_path (passed through to AARE) - log_event (passed through to AARE) ''' if rulepart == self.ALL: return None, True elif type_is_str(rulepart): if len(rulepart.strip()) == 0: raise AppArmorBug( 'Passed empty %(partname)s to %(classname)s: %(rulepart)s' % { 'partname': partname, 'classname': self.__class__.__name__, 'rulepart': str(rulepart) }) return AARE(rulepart, is_path=is_path, log_event=log_event), False else: raise AppArmorBug( 'Passed unknown %(partname)s to %(classname)s: %(rulepart)s' % { 'partname': partname, 'classname': self.__class__.__name__, 'rulepart': str(rulepart) })
def check_and_split_list(lst, allowed_keywords, all_obj, classname, keyword_name): '''check if lst is all_obj or contains only items listed in allowed_keywords''' if lst == all_obj: return None, True, None elif type_is_str(lst): result_list = {lst} elif (type(lst) == list or type(lst) == tuple) and len(lst) > 0: result_list = set(lst) else: raise AppArmorBug( 'Passed unknown %(type)s object to %(classname)s: %(unknown_object)s' % { 'type': type(lst), 'classname': classname, 'unknown_object': str(lst) }) unknown_items = set() for item in result_list: if not item.strip(): raise AppArmorBug( 'Passed empty %(keyword_name)s to %(classname)s' % { 'keyword_name': keyword_name, 'classname': classname }) if item not in allowed_keywords: unknown_items.add(item) return result_list, False, unknown_items
def __init__(self, cap_list, audit=False, deny=False, allow_keyword=False, comment='', log_event=None): super(CapabilityRule, self).__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, log_event=log_event) # Because we support having multiple caps in one rule, # initializer needs to accept a list of caps. self.all_caps = False if cap_list == CapabilityRule.ALL: self.all_caps = True self.capability = set() else: if type_is_str(cap_list): self.capability = {cap_list} elif type(cap_list) == list and len(cap_list) > 0: self.capability = set(cap_list) else: raise AppArmorBug('Passed unknown object to CapabilityRule: %s' % str(cap_list)) # make sure none of the cap_list arguments are blank, in # case we decide to return one cap per output line for cap in self.capability: if len(cap.strip()) == 0: raise AppArmorBug('Passed empty capability to CapabilityRule: %s' % str(cap_list))
def __init__(self, domain, type_or_protocol, audit=False, deny=False, allow_keyword=False, comment='', log_event=None): 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_is_str(domain): if domain in network_domain_keywords: self.domain = domain else: raise AppArmorBug('Passed unknown domain to NetworkRule: %s' % domain) 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_is_str(type_or_protocol): if type_or_protocol in network_protocol_keywords: self.type_or_protocol = type_or_protocol elif type_or_protocol in network_type_keywords: self.type_or_protocol = type_or_protocol else: raise AppArmorBug( 'Passed unknown type_or_protocol to NetworkRule: %s' % type_or_protocol) else: raise AppArmorBug('Passed unknown object to NetworkRule: %s' % str(type_or_protocol))
def __init__(self, execmode, execcond, targetprofile, audit=False, deny=False, allow_keyword=False, comment='', log_event=None): ''' CHANGE_PROFILE RULE = 'change_profile' [ [ EXEC MODE ] EXEC COND ] [ -> PROGRAMCHILD ] ''' super(ChangeProfileRule, self).__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, log_event=log_event) if execmode: if execmode != 'safe' and execmode != 'unsafe': raise AppArmorBug('Unknown exec mode (%s) in change_profile rule' % execmode) elif not execcond or execcond == ChangeProfileRule.ALL: raise AppArmorException('Exec condition is required when unsafe or safe keywords are present') self.execmode = execmode self.execcond = None self.all_execconds = False if execcond == ChangeProfileRule.ALL: self.all_execconds = True elif type_is_str(execcond): if not execcond.strip(): raise AppArmorBug('Empty exec condition in change_profile rule') elif execcond.startswith('/') or execcond.startswith('@'): self.execcond = execcond else: raise AppArmorException('Exec condition in change_profile rule does not start with /: %s' % str(execcond)) else: raise AppArmorBug('Passed unknown object to ChangeProfileRule: %s' % str(execcond)) self.targetprofile = None self.all_targetprofiles = False if targetprofile == ChangeProfileRule.ALL: self.all_targetprofiles = True elif type_is_str(targetprofile): if targetprofile.strip(): self.targetprofile = targetprofile else: raise AppArmorBug('Empty target profile in change_profile rule') else: raise AppArmorBug('Passed unknown object to ChangeProfileRule: %s' % str(targetprofile))
def __init__(self, orig_path, target, audit=False, deny=False, allow_keyword=False, comment='', log_event=None): super(AliasRule, self).__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, log_event=log_event) # aliass don't support audit or deny if audit: raise AppArmorBug('Attempt to initialize %s with audit flag' % self.__class__.__name__) if deny: raise AppArmorBug('Attempt to initialize %s with deny flag' % self.__class__.__name__) if not type_is_str(orig_path): raise AppArmorBug('Passed unknown type for orig_path to %s: %s' % (self.__class__.__name__, orig_path)) if not orig_path: raise AppArmorException('Passed empty orig_path to %s: %s' % (self.__class__.__name__, orig_path)) if not orig_path.startswith('/'): raise AppArmorException("Alias path doesn't start with '/'") if not type_is_str(target): raise AppArmorBug('Passed unknown type for target to %s: %s' % (self.__class__.__name__, target)) if not target: raise AppArmorException('Passed empty target to %s: %s' % (self.__class__.__name__, target)) if not target.startswith('/'): raise AppArmorException("Alias target doesn't start with '/'") self.orig_path = orig_path self.target = target
def add_or_remove_flag(flags, flags_to_change, set_flag): '''add (if set_flag == True) or remove the given flags_to_change to flags''' if type_is_str(flags) or flags is None: flags = split_flags(flags) if type_is_str(flags_to_change) or flags_to_change is None: flags_to_change = split_flags(flags_to_change) if set_flag: for flag_to_change in flags_to_change: if flag_to_change not in flags: flags.append(flag_to_change) else: for flag_to_change in flags_to_change: if flag_to_change in flags: flags.remove(flag_to_change) return sorted(flags)
def is_equal(self, expression): '''check if the given expression is equal''' if type(expression) == AARE: return self.regex == expression.regex elif type_is_str(expression): return self.regex == expression else: raise AppArmorBug( 'AARE.is_equal() called with unknown object: %s' % str(expression))
def __init__(self, execcond, targetprofile, audit=False, deny=False, allow_keyword=False, comment='', log_event=None): ''' CHANGE_PROFILE RULE = 'change_profile' [ EXEC COND ] [ -> PROGRAMCHILD ] ''' super(ChangeProfileRule, self).__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, log_event=log_event) self.execcond = None self.all_execconds = False if execcond == ChangeProfileRule.ALL: self.all_execconds = True elif type_is_str(execcond): if not execcond.strip(): raise AppArmorBug('Empty exec condition in change_profile rule') elif execcond.startswith('/') or execcond.startswith('@'): self.execcond = execcond else: raise AppArmorException('Exec condition in change_profile rule does not start with /: %s' % str(execcond)) else: raise AppArmorBug('Passed unknown object to ChangeProfileRule: %s' % str(execcond)) self.targetprofile = None self.all_targetprofiles = False if targetprofile == ChangeProfileRule.ALL: self.all_targetprofiles = True elif type_is_str(targetprofile): if targetprofile.strip(): self.targetprofile = targetprofile else: raise AppArmorBug('Empty target profile in change_profile rule') else: raise AppArmorBug('Passed unknown object to ChangeProfileRule: %s' % str(targetprofile))
def match(self, expression): '''check if the given expression (string or AARE) matches the regex''' if type(expression) == AARE: if expression.orig_regex: expression = expression.orig_regex else: return self.is_equal(expression) # better safe than sorry elif not type_is_str(expression): raise AppArmorBug('AARE.match() called with unknown object: %s' % str(expression)) if self._regex_compiled is None: self._regex_compiled = re.compile(convert_regexp(self.regex)) return bool(self._regex_compiled.match(expression))
def __init__(self, path, ifexists, ismagic, audit=False, deny=False, allow_keyword=False, comment='', log_event=None): super(IncludeRule, self).__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, log_event=log_event) # include doesn't support audit or deny if audit: raise AppArmorBug('Attempt to initialize %s with audit flag' % self.__class__.__name__) if deny: raise AppArmorBug('Attempt to initialize %s with deny flag' % self.__class__.__name__) if type(ifexists) is not bool: raise AppArmorBug('Passed unknown type for ifexists to %s: %s' % (self.__class__.__name__, ifexists)) if type(ismagic) is not bool: raise AppArmorBug('Passed unknown type for ismagic to %s: %s' % (self.__class__.__name__, ismagic)) if not type_is_str(path): raise AppArmorBug('Passed unknown type for path to %s: %s' % (self.__class__.__name__, path)) if not path: raise AppArmorBug('Passed empty path to %s: %s' % (self.__class__.__name__, path)) self.path = path self.ifexists = ifexists self.ismagic = ismagic
def _run_test(self, params, expected): self.assertEqual(type_is_str(params), expected)
def __init__(self, path, perms, exec_perms, target, owner, file_keyword=False, leading_perms=False, audit=False, deny=False, allow_keyword=False, comment='', log_event=None): '''Initialize FileRule Parameters: - path: string, AARE or FileRule.ALL - perms: string, set of chars or FileRule.ALL (must not contain exec mode) - exec_perms: None or string - target: string, AARE or FileRule.ALL - owner: bool - file_keyword: bool - leading_perms: bool ''' super(FileRule, self).__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, log_event=log_event) # rulepart partperms is_path log_event self.path, self.all_paths = self._aare_or_all(path, 'path', True, log_event) self.target, self.all_targets, = self._aare_or_all( target, 'target', False, log_event) self.can_glob = not self.all_paths self.can_glob_ext = not self.all_paths self.can_edit = not self.all_paths if type_is_str(perms): perms, tmp_exec_perms = split_perms(perms, deny) if tmp_exec_perms: raise AppArmorBug('perms must not contain exec perms') elif perms == None: perms = set() if perms == {'subset'}: raise AppArmorBug('subset without link permissions given') elif perms in [{'link'}, {'link', 'subset'}]: self.perms = perms self.all_perms = False else: self.perms, self.all_perms, unknown_items = check_and_split_list( perms, file_permissions, FileRule.ALL, 'FileRule', 'permissions', allow_empty_list=True) if unknown_items: raise AppArmorBug('Passed unknown perms to FileRule: %s' % str(unknown_items)) if self.perms and 'a' in self.perms and 'w' in self.perms: raise AppArmorException( "Conflicting permissions found: 'a' and 'w'") self.original_perms = None # might be set by aa-logprof / aa.py propose_file_rules() if exec_perms is None: self.exec_perms = None elif 'link' in self.perms: raise AppArmorBug("link rules can't have execute permissions") elif exec_perms == self.ANY_EXEC: self.exec_perms = exec_perms elif type_is_str(exec_perms): if deny: if exec_perms != 'x': raise AppArmorException( _("file deny rules only allow to use 'x' as execute mode, but not %s" % exec_perms)) else: if exec_perms == 'x': raise AppArmorException( _("Execute flag ('x') in file rule must specify the exec mode (ix, Px, Cx etc.)" )) elif exec_perms not in allow_exec_transitions and exec_perms not in allow_exec_fallback_transitions: raise AppArmorBug( 'Unknown execute mode specified in file rule: %s' % exec_perms) self.exec_perms = exec_perms else: raise AppArmorBug('Passed unknown perms object to FileRule: %s' % str(perms)) if type(owner) is not bool: raise AppArmorBug('non-boolean value passed to owner flag') self.owner = owner self.can_owner = owner # offer '(O)wner permissions on/off' buttons only if the rule has the owner flag if type(file_keyword) is not bool: raise AppArmorBug('non-boolean value passed to file keyword flag') self.file_keyword = file_keyword if type(leading_perms) is not bool: raise AppArmorBug( 'non-boolean value passed to leading permissions flag') self.leading_perms = leading_perms # XXX subset # check for invalid combinations (bare 'file,' vs. path rule) # if (self.all_paths and not self.all_perms) or (not self.all_paths and self.all_perms): # raise AppArmorBug('all_paths and all_perms must be equal') # elif if self.all_paths and (self.exec_perms or self.target): raise AppArmorBug( 'exec perms or target specified for bare file rule')
def _run_test(self, params, expected): self.assertEqual(type_is_str(params), expected)