Adjust type(x) == str checks in the rule classes for py2

python 3 uses only the 'str' type, while python 2 also uses 'unicode'.
This patch adds a type_is_str() function to common.py - depending on the
python version, it checks for both. This helper function is used to keep
the complexity outside of the rule classes.

The rule classes get adjusted to use type_is_str() instead of checking
for type(x) == str, which means they support both python versions.

As pointed out by Tyler, there are also some type(...) == str checks in
aare.py and rule/__init__.py which should get the same change.

Finally, add test-common.py with some tests for type_is_str().


References: https://bugs.launchpad.net/apparmor/+bug/1513880


Acked-by: Tyler Hicks <tyhicks@canonical.com> for trunk and 2.10

Note: 2.10 doesn't contain SignalRule, therefore it doesn't get that
part of the patch.
This commit is contained in:
Christian Boltz 2015-12-17 23:33:36 +01:00
parent 3073160aca
commit 6f63cf3664
9 changed files with 59 additions and 18 deletions

View file

@ -14,7 +14,7 @@
import re
from apparmor.common import convert_regexp, AppArmorBug, AppArmorException
from apparmor.common import convert_regexp, type_is_str, AppArmorBug, AppArmorException
class AARE(object):
'''AARE (AppArmor Regular Expression) wrapper class'''
@ -54,7 +54,7 @@ class AARE(object):
expression = expression.orig_regex
else:
return self.is_equal(expression) # better safe than sorry
elif type(expression) != str:
elif not type_is_str(expression):
raise AppArmorBug('AARE.match() called with unknown object: %s' % str(expression))
if self._regex_compiled is None:
@ -67,7 +67,7 @@ class AARE(object):
if type(expression) == AARE:
return self.regex == expression.regex
elif type(expression) == str:
elif type_is_str(expression):
return self.regex == expression
else:
raise AppArmorBug('AARE.is_equal() called with unknown object: %s' % str(expression))

View file

@ -245,6 +245,15 @@ def user_perm(prof_dir):
return False
return True
def type_is_str(var):
''' returns True if the given variable is a str (or unicode string when using python 2)'''
if type(var) == str:
return True
elif sys.version_info[0] < 3 and type(var) == unicode: # python 2 sometimes uses the 'unicode' type
return True
else:
return False
class DebugLogger(object):
def __init__(self, module_name=__name__):
self.debugging = False

View file

@ -13,7 +13,7 @@
#
# ----------------------------------------------------------------------
from apparmor.common import AppArmorBug
from apparmor.common import AppArmorBug, type_is_str
# setup module translations
from apparmor.translations import init_translation
@ -348,7 +348,7 @@ def check_and_split_list(lst, allowed_keywords, all_obj, classname, keyword_name
if lst == all_obj:
return None, True, None
elif type(lst) == str:
elif type_is_str(lst):
result_list = {lst}
elif (type(lst) == list or type(lst) == tuple) and len(lst) > 0:
result_list = set(lst)

View file

@ -14,7 +14,7 @@
# ----------------------------------------------------------------------
from apparmor.regex import RE_PROFILE_CAP
from apparmor.common import AppArmorBug, AppArmorException
from apparmor.common import AppArmorBug, AppArmorException, type_is_str
from apparmor.rule import BaseRule, BaseRuleset, parse_modifiers
import re
@ -47,7 +47,7 @@ class CapabilityRule(BaseRule):
self.all_caps = True
self.capability = set()
else:
if type(cap_list) == str:
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)

View file

@ -14,7 +14,7 @@
# ----------------------------------------------------------------------
from apparmor.regex import RE_PROFILE_CHANGE_PROFILE, strip_quotes
from apparmor.common import AppArmorBug, AppArmorException
from apparmor.common import AppArmorBug, AppArmorException, type_is_str
from apparmor.rule import BaseRule, BaseRuleset, parse_modifiers, quote_if_needed
# setup module translations
@ -48,7 +48,7 @@ class ChangeProfileRule(BaseRule):
self.all_execconds = False
if execcond == ChangeProfileRule.ALL:
self.all_execconds = True
elif type(execcond) == str:
elif type_is_str(execcond):
if not execcond.strip():
raise AppArmorBug('Empty exec condition in change_profile rule')
elif execcond.startswith('/') or execcond.startswith('@'):
@ -62,7 +62,7 @@ class ChangeProfileRule(BaseRule):
self.all_targetprofiles = False
if targetprofile == ChangeProfileRule.ALL:
self.all_targetprofiles = True
elif type(targetprofile) == str:
elif type_is_str(targetprofile):
if targetprofile.strip():
self.targetprofile = targetprofile
else:

View file

@ -16,7 +16,7 @@
import re
from apparmor.regex import RE_PROFILE_NETWORK
from apparmor.common import AppArmorBug, AppArmorException
from apparmor.common import AppArmorBug, AppArmorException, type_is_str
from apparmor.rule import BaseRule, BaseRuleset, parse_modifiers
# setup module translations
@ -66,7 +66,7 @@ class NetworkRule(BaseRule):
self.all_domains = False
if domain == NetworkRule.ALL:
self.all_domains = True
elif type(domain) == str:
elif type_is_str(domain):
if domain in network_domain_keywords:
self.domain = domain
else:
@ -78,7 +78,7 @@ class NetworkRule(BaseRule):
self.all_type_or_protocols = False
if type_or_protocol == NetworkRule.ALL:
self.all_type_or_protocols = True
elif type(type_or_protocol) == str:
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:

View file

@ -16,7 +16,7 @@
import re
from apparmor.regex import RE_PROFILE_RLIMIT, strip_quotes
from apparmor.common import AppArmorBug, AppArmorException
from apparmor.common import AppArmorBug, AppArmorException, type_is_str
from apparmor.rule import BaseRule, BaseRuleset, parse_comment, quote_if_needed
# setup module translations
@ -57,7 +57,7 @@ class RlimitRule(BaseRule):
if audit or deny or allow_keyword:
raise AppArmorBug('The audit, allow or deny keywords are not allowed in rlimit rules.')
if type(rlimit) == str:
if type_is_str(rlimit):
if rlimit in rlimit_all:
self.rlimit = rlimit
else:
@ -70,7 +70,7 @@ class RlimitRule(BaseRule):
self.all_values = False
if value == RlimitRule.ALL:
self.all_values = True
elif type(value) == str:
elif type_is_str(value):
if not value.strip():
raise AppArmorBug('Empty value in rlimit rule')

View file

@ -16,7 +16,7 @@ import re
from apparmor.aare import AARE
from apparmor.regex import RE_PROFILE_SIGNAL, RE_PROFILE_NAME
from apparmor.common import AppArmorBug, AppArmorException
from apparmor.common import AppArmorBug, AppArmorException, type_is_str
from apparmor.rule import BaseRule, BaseRuleset, check_and_split_list, parse_modifiers, quote_if_needed
# setup module translations
@ -96,7 +96,7 @@ class SignalRule(BaseRule):
self.all_peers = False
if peer == SignalRule.ALL:
self.all_peers = True
elif type(peer) == str:
elif type_is_str(peer):
if len(peer.strip()) == 0:
raise AppArmorBug('Passed empty peer to SignalRule: %s' % str(peer))
self.peer = AARE(peer, False, log_event=log_event)

32
utils/test/test-common.py Normal file
View file

@ -0,0 +1,32 @@
#! /usr/bin/env python
# ------------------------------------------------------------------
#
# Copyright (C) 2015 Christian Boltz <apparmor@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 published by the Free Software Foundation.
#
# ------------------------------------------------------------------
import unittest
from common_test import AATest, setup_all_loops
from apparmor.common import type_is_str
class TestIs_str_type(AATest):
tests = [
('foo', True),
(u'foo', True),
(42, False),
(True, False),
([], False),
]
def _run_test(self, params, expected):
self.assertEqual(type_is_str(params), expected)
setup_all_loops(__name__)
if __name__ == '__main__':
unittest.main(verbosity=2)