2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-31 14:25:52 +00:00

Merge Resolve string escape sequence DeprecationWarnings

This MR closes #286.

Strings with only invalid escape sequences were prefixed with an `r`. Strings containing both valid and invalid escape sequences were handled on a case-by-case basis, as simply changing to a raw string breaks valid escape sequences.

Closes #286
MR: https://gitlab.com/apparmor/apparmor/-/merge_requests/951
Approved-by: Christian Boltz <apparmor@cboltz.de>
Merged-by: Christian Boltz <apparmor@cboltz.de>
This commit is contained in:
Christian Boltz
2022-11-22 12:40:55 +00:00
19 changed files with 152 additions and 152 deletions

View File

@@ -49,8 +49,8 @@ def last_audit_entry_time():
out = subprocess.check_output(['tail', '-1', apparmor.logfile])
logmark = None
out = out.decode('ascii')
if re.search('^.*msg\=audit\((\d+\.\d+\:\d+).*\).*$', out):
logmark = re.search('^.*msg\=audit\((\d+\.\d+\:\d+).*\).*$', out).groups()[0]
if re.search(r'^.*msg=audit\((\d+\.\d+:\d+).*\).*$', out):
logmark = re.search(r'^.*msg=audit\((\d+\.\d+:\d+).*\).*$', out).groups()[0]
else:
logmark = ''
return logmark

View File

@@ -255,18 +255,18 @@ def get_apparmor_events(logfile, since=0):
def parse_logdata(logsource):
"""Traverse any iterable log source and extract relevant AppArmor events"""
re_audit_time_id = '(msg=)?audit\([\d\.\:]+\):\s+' # 'audit(1282626827.320:411): '
re_kernel_time = '\[[\d\.\s]+\]' # '[ 1612.746129]'
re_type_num = '1[45][0-9][0-9]' # 1400..1599
re_audit_time_id = r'(msg=)?audit\([\d\.\:]+\):\s+' # 'audit(1282626827.320:411): '
re_kernel_time = r'\[[\d\.\s]+\]' # '[ 1612.746129]'
re_type_num = '1[45][0-9][0-9]' # 1400..1599
re_aa_or_op = '(apparmor=|operation=)'
re_log_parts = [
'kernel:\s+(' + re_kernel_time + '\s+)?(audit:\s+)?type=' + re_type_num + '\s+' + re_audit_time_id + re_aa_or_op, # v2_6 syslog
'kernel:\s+(' + re_kernel_time + '\s+)?' + re_audit_time_id + 'type=' + re_type_num + '\s+' + re_aa_or_op,
'type=(AVC|APPARMOR[_A-Z]*|' + re_type_num + ')\s+' + re_audit_time_id + '(type=' + re_type_num + '\s+)?' + re_aa_or_op, # v2_6 audit and dmesg
'type=USER_AVC\s+' + re_audit_time_id + '.*apparmor=', # dbus
'type=UNKNOWN\[' + re_type_num + '\]\s+' + re_audit_time_id + re_aa_or_op,
'dbus\[[0-9]+\]:\s+apparmor=', # dbus
r'kernel:\s+(' + re_kernel_time + r'\s+)?(audit:\s+)?type=' + re_type_num + r'\s+' + re_audit_time_id + re_aa_or_op, # v2_6 syslog
r'kernel:\s+(' + re_kernel_time + r'\s+)?' + re_audit_time_id + 'type=' + re_type_num + r'\s+' + re_aa_or_op,
'type=(AVC|APPARMOR[_A-Z]*|' + re_type_num + r')\s+' + re_audit_time_id + '(type=' + re_type_num + r'\s+)?' + re_aa_or_op, # v2_6 audit and dmesg
r'type=USER_AVC\s+' + re_audit_time_id + '.*apparmor=', # dbus
r'type=UNKNOWN\[' + re_type_num + r'\]\s+' + re_audit_time_id + re_aa_or_op,
r'dbus\[[0-9]+\]:\s+apparmor=', # dbus
]
# Pre-filter log lines so that we hand over only relevant lines to LibAppArmor parsing

View File

@@ -78,7 +78,7 @@ def get_pids_ss(ss='ss'):
def get_pids_netstat(netstat='netstat'):
"""Get a set of pids listening on network sockets via netstat(8)"""
regex_tcp_udp = re.compile(r"^(tcp|udp|raw)6?\s+\d+\s+\d+\s+\S+\:(\d+)\s+\S+\:(\*|\d+)\s+(LISTEN|\d+|\s+)\s+(?P<pid>\d+)\/(\S+)")
regex_tcp_udp = re.compile(r"^(tcp|udp|raw)6?\s+\d+\s+\d+\s+\S+:(\d+)\s+\S+:(\*|\d+)\s+(LISTEN|\d+|\s+)\s+(?P<pid>\d+)/(\S+)")
cmd = [netstat, '-nlp', '--protocol', 'inet,inet6']
my_env = os.environ.copy()

View File

@@ -360,8 +360,8 @@ def get_output(params):
def get_reqs(file):
"""Returns a list of paths from ldd output"""
pattern1 = re.compile('^\s*\S+ => (\/\S+)')
pattern2 = re.compile('^\s*(\/\S+)')
pattern1 = re.compile(r'^\s*\S+ => (/\S+)')
pattern2 = re.compile(r'^\s*(/\S+)')
reqs = []
ldd = conf.find_first_file(cfg['settings'].get('ldd')) or '/usr/bin/ldd'
@@ -439,9 +439,9 @@ def get_interpreter_and_abstraction(exec_target):
abstraction = 'abstractions/bash'
elif interpreter == 'perl':
abstraction = 'abstractions/perl'
elif re.search('^python([23]|[23]\.[0-9]+)?$', interpreter):
elif re.search(r'^python([23]|[23]\.[0-9]+)?$', interpreter):
abstraction = 'abstractions/python'
elif re.search('^ruby([0-9]+(\.[0-9]+)*)?$', interpreter):
elif re.search(r'^ruby([0-9]+(\.[0-9]+)*)?$', interpreter):
abstraction = 'abstractions/ruby'
else:
abstraction = None
@@ -2526,10 +2526,10 @@ def loadincludes_dir(subdir, in_preamble):
def glob_common(path):
globs = []
if re.search('[\d\.]+\.so$', path) or re.search('\.so\.[\d\.]+$', path):
if re.search(r'[\d.]+\.so$', path) or re.search(r'\.so\.[\d.]+$', path):
libpath = path
libpath = re.sub('[\d\.]+\.so$', '*.so', libpath)
libpath = re.sub('\.so\.[\d\.]+$', '.so.*', libpath)
libpath = re.sub(r'[\d.]+\.so$', '*.so', libpath)
libpath = re.sub(r'\.so\.[\d.]+$', '.so.*', libpath)
if libpath != path:
globs.append(libpath)

View File

@@ -92,25 +92,25 @@ class AARE:
if self.regex.endswith('/'):
if self.regex.endswith(('/**/', '/*/')):
# /foo/**/ and /foo/*/ => /**/
newpath = re.sub('/[^/]+/\*{1,2}/$', '/**/', self.regex) # re.sub('/[^/]+/\*{1,2}$/', '/\*\*/', self.regex)
elif re.search('/[^/]+\*\*[^/]*/$', self.regex):
newpath = re.sub(r'/[^/]+/\*{1,2}/$', '/**/', self.regex)
elif re.search(r'/[^/]+\*\*[^/]*/$', self.regex):
# /foo**/ and /foo**bar/ => /**/
newpath = re.sub('/[^/]+\*\*[^/]*/$', '/**/', self.regex)
elif re.search('/\*\*[^/]+/$', self.regex):
newpath = re.sub(r'/[^/]+\*\*[^/]*/$', '/**/', self.regex)
elif re.search(r'/\*\*[^/]+/$', self.regex):
# /**bar/ => /**/
newpath = re.sub('/\*\*[^/]+/$', '/**/', self.regex)
newpath = re.sub(r'/\*\*[^/]+/$', '/**/', self.regex)
else:
newpath = re.sub('/[^/]+/$', '/*/', self.regex)
else:
if self.regex.endswith(('/**', '/*')):
# /foo/** and /foo/* => /**
newpath = re.sub('/[^/]+/\*{1,2}$', '/**', self.regex)
elif re.search('/[^/]*\*\*[^/]+$', self.regex):
newpath = re.sub(r'/[^/]+/\*{1,2}$', '/**', self.regex)
elif re.search(r'/[^/]*\*\*[^/]+$', self.regex):
# /**foo and /foor**bar => /**
newpath = re.sub('/[^/]*\*\*[^/]+$', '/**', self.regex)
elif re.search('/[^/]+\*\*$', self.regex):
newpath = re.sub(r'/[^/]*\*\*[^/]+$', '/**', self.regex)
elif re.search(r'/[^/]+\*\*$', self.regex):
# /foo** => /**
newpath = re.sub('/[^/]+\*\*$', '/**', self.regex)
newpath = re.sub(r'/[^/]+\*\*$', '/**', self.regex)
else:
newpath = re.sub('/[^/]+$', '/*', self.regex)
return type(self)(newpath, False)
@@ -119,23 +119,23 @@ class AARE:
"""Glob given file path with extension
Files without extensions and directories won't be changed"""
# match /**.ext and /*.ext
match = re.search('/\*{1,2}(\.[^/]+)$', self.regex)
match = re.search(r'/\*{1,2}(\.[^/]+)$', self.regex)
if match:
# /foo/**.ext and /foo/*.ext => /**.ext
newpath = re.sub('/[^/]+/\*{1,2}\.[^/]+$', '/**' + match.groups()[0], self.regex)
elif re.search('/[^/]+\*\*[^/]*\.[^/]+$', self.regex):
newpath = re.sub(r'/[^/]+/\*{1,2}\.[^/]+$', '/**' + match.groups()[0], self.regex)
elif re.search(r'/[^/]+\*\*[^/]*\.[^/]+$', self.regex):
# /foo**.ext and /foo**bar.ext => /**.ext
match = re.search('/[^/]+\*\*[^/]*(\.[^/]+)$', self.regex)
newpath = re.sub('/[^/]+\*\*[^/]*\.[^/]+$', '/**' + match.groups()[0], self.regex)
elif re.search('/\*\*[^/]+\.[^/]+$', self.regex):
match = re.search(r'/[^/]+\*\*[^/]*(\.[^/]+)$', self.regex)
newpath = re.sub(r'/[^/]+\*\*[^/]*\.[^/]+$', '/**' + match.groups()[0], self.regex)
elif re.search(r'/\*\*[^/]+\.[^/]+$', self.regex):
# /**foo.ext => /**.ext
match = re.search('/\*\*[^/]+(\.[^/]+)$', self.regex)
newpath = re.sub('/\*\*[^/]+\.[^/]+$', '/**' + match.groups()[0], self.regex)
match = re.search(r'/\*\*[^/]+(\.[^/]+)$', self.regex)
newpath = re.sub(r'/\*\*[^/]+\.[^/]+$', '/**' + match.groups()[0], self.regex)
else:
newpath = self.regex
match = re.search('(\.[^/]+)$', self.regex)
match = re.search(r'(\.[^/]+)$', self.regex)
if match:
newpath = re.sub('/[^/]+(\.[^/]+)$', '/*' + match.groups()[0], self.regex)
newpath = re.sub(r'/[^/]+(\.[^/]+)$', '/*' + match.groups()[0], self.regex)
return type(self)(newpath, False)

View File

@@ -229,7 +229,7 @@ def convert_regexp(regexp):
regexp = regexp.replace('(', '\\(').replace(')', '\\)') # escape '(' and ')'
new_reg = re.sub(r'(?<!\\)(\.|\+|\$)', r'\\\1', regexp)
new_reg = re.sub(r'(?<!\\)([.+$])', r'\\\1', regexp)
while regex_paren.search(new_reg):
match = regex_paren.search(new_reg).groups()

View File

@@ -156,7 +156,7 @@ def valid_path(path, relative_ok=False):
def _is_safe(s):
"""Known safe regex"""
if re.search(r'^[a-zA-Z_0-9\-\.]+$', s):
if re.search(r'^[a-zA-Z_0-9\-.]+$', s):
return True
return False
@@ -199,7 +199,7 @@ def valid_profile_name(s):
# profile name does not specify path
# alphanumeric and Debian version, plus '_'
if re.search(r'^[a-zA-Z0-9][a-zA-Z0-9_\+\-\.:~]+$', s):
if re.search(r'^[a-zA-Z0-9][a-zA-Z0-9_+\-.:~]+$', s):
return True
return False
@@ -372,10 +372,10 @@ class AppArmorEasyProfile:
if not pat.search(line):
continue
if line.startswith("POLICYGROUPS_DIR="):
d = re.split(r'=', line.strip())[1].strip('["\']')
d = re.split('=', line.strip())[1].strip('["\']')
self.dirs['policygroups'] = d
elif line.startswith("TEMPLATES_DIR="):
d = re.split(r'=', line.strip())[1].strip('["\']')
d = re.split('=', line.strip())[1].strip('["\']')
self.dirs['templates'] = d
keys = self.dirs.keys()
@@ -1168,7 +1168,7 @@ def verify_manifest(params, args=None):
if a not in safe_abstractions:
err_str += "\nfound '%s' abstraction" % a
elif k == "template_var":
pat = re.compile(r'[*/\{\}\[\]]')
pat = re.compile(r'[*/{}\[\]]')
for tv in params['template_var']:
if not fake_easyp.gen_variable_declaration(tv):
err_str += "\n%s" % tv

View File

@@ -21,68 +21,68 @@ from apparmor.translations import init_translation
_ = init_translation()
# Profile parsing Regex
RE_AUDIT_DENY = '^\s*(?P<audit>audit\s+)?(?P<allow>allow\s+|deny\s+)?' # line start, optionally: leading whitespace, <audit> and <allow>/deny
RE_EOL = '\s*(?P<comment>#.*?)?\s*$' # optional whitespace, optional <comment>, optional whitespace, end of the line
RE_COMMA_EOL = '\s*,' + RE_EOL # optional whitespace, comma + RE_EOL
RE_AUDIT_DENY = r'^\s*(?P<audit>audit\s+)?(?P<allow>allow\s+|deny\s+)?' # line start, optionally: leading whitespace, <audit> and <allow>/deny
RE_EOL = r'\s*(?P<comment>#.*?)?\s*$' # optional whitespace, optional <comment>, optional whitespace, end of the line
RE_COMMA_EOL = r'\s*,' + RE_EOL # optional whitespace, comma + RE_EOL
RE_PROFILE_NAME = '(?P<%s>(\S+|"[^"]+"))' # string without spaces, or quoted string. %s is the match group name
RE_PATH = '/\S*|"/[^"]*"' # filename (starting with '/') without spaces, or quoted filename.
RE_PROFILE_NAME = r'(?P<%s>(\S+|"[^"]+"))' # string without spaces, or quoted string. %s is the match group name
RE_PATH = r'/\S*|"/[^"]*"' # filename (starting with '/') without spaces, or quoted filename.
RE_PROFILE_PATH = '(?P<%s>(' + RE_PATH + '))' # quoted or unquoted filename. %s is the match group name
RE_PROFILE_PATH_OR_VAR = '(?P<%s>(' + RE_PATH + '|@{\S+}\S*|"@{\S+}[^"]*"))' # quoted or unquoted filename or variable. %s is the match group name
RE_PROFILE_PATH_OR_VAR = '(?P<%s>(' + RE_PATH + r'|@{\S+}\S*|"@{\S+}[^"]*"))' # quoted or unquoted filename or variable. %s is the match group name
RE_SAFE_OR_UNSAFE = '(?P<execmode>(safe|unsafe))'
RE_XATTRS = '(\s+xattrs\s*=\s*\((?P<xattrs>([^)=]+(=[^)=]+)?\s?)+)\)\s*)?'
RE_FLAGS = '(\s+(flags\s*=\s*)?\((?P<flags>[^)]+)\))?'
RE_XATTRS = r'(\s+xattrs\s*=\s*\((?P<xattrs>([^)=]+(=[^)=]+)?\s?)+)\)\s*)?'
RE_FLAGS = r'(\s+(flags\s*=\s*)?\((?P<flags>[^)]+)\))?'
RE_PROFILE_END = re.compile('^\s*\}' + RE_EOL)
RE_PROFILE_CAP = re.compile(RE_AUDIT_DENY + 'capability(?P<capability>(\s+\S+)+)?' + RE_COMMA_EOL)
RE_PROFILE_ALIAS = re.compile('^\s*alias\s+(?P<orig_path>"??.+?"??)\s+->\s*(?P<target>"??.+?"??)' + RE_COMMA_EOL)
RE_PROFILE_RLIMIT = re.compile('^\s*set\s+rlimit\s+(?P<rlimit>[a-z]+)\s*<=\s*(?P<value>[^ ]+(\s+[a-zA-Z]+)?)' + RE_COMMA_EOL)
RE_PROFILE_BOOLEAN = re.compile('^\s*(?P<varname>\$\{?\w*\}?)\s*=\s*(?P<value>true|false)\s*,?' + RE_EOL, flags=re.IGNORECASE)
RE_PROFILE_VARIABLE = re.compile('^\s*(?P<varname>@\{?\w+\}?)\s*(?P<mode>\+?=)\s*(?P<values>@*.+?)' + RE_EOL)
RE_PROFILE_CONDITIONAL = re.compile('^\s*if\s+(not\s+)?(\$\{?\w*\}?)\s*\{' + RE_EOL)
RE_PROFILE_CONDITIONAL_VARIABLE = re.compile('^\s*if\s+(not\s+)?defined\s+(@\{?\w+\}?)\s*\{\s*(#.*)?$')
RE_PROFILE_CONDITIONAL_BOOLEAN = re.compile('^\s*if\s+(not\s+)?defined\s+(\$\{?\w+\}?)\s*\{\s*(#.*)?$')
RE_PROFILE_NETWORK = re.compile(RE_AUDIT_DENY + 'network(?P<details>\s+.*)?' + RE_COMMA_EOL)
RE_PROFILE_CHANGE_HAT = re.compile('^\s*\^(\"??.+?\"??)' + RE_COMMA_EOL)
RE_PROFILE_HAT_DEF = re.compile('^(?P<leadingspace>\s*)(?P<hat_keyword>\^|hat\s+)(?P<hat>\"??[^)]+?\"??)' + RE_FLAGS + '\s*\{' + RE_EOL)
RE_PROFILE_DBUS = re.compile(RE_AUDIT_DENY + '(dbus\s*,|dbus(?P<details>\s+[^#]*)\s*,)' + RE_EOL)
RE_PROFILE_MOUNT = re.compile(RE_AUDIT_DENY + '((mount|remount|umount|unmount)(\s+[^#]*)?\s*,)' + RE_EOL)
RE_PROFILE_SIGNAL = re.compile(RE_AUDIT_DENY + '(signal\s*,|signal(?P<details>\s+[^#]*)\s*,)' + RE_EOL)
RE_PROFILE_PTRACE = re.compile(RE_AUDIT_DENY + '(ptrace\s*,|ptrace(?P<details>\s+[^#]*)\s*,)' + RE_EOL)
RE_PROFILE_PIVOT_ROOT = re.compile(RE_AUDIT_DENY + '(pivot_root\s*,|pivot_root\s+[^#]*\s*,)' + RE_EOL)
RE_PROFILE_UNIX = re.compile(RE_AUDIT_DENY + '(unix\s*,|unix\s+[^#]*\s*,)' + RE_EOL)
RE_PROFILE_USERNS = re.compile(RE_AUDIT_DENY + '(userns\s*,|userns(?P<details>\s+[^#]*)\s*,)' + RE_EOL)
RE_PROFILE_END = re.compile(r'^\s*\}' + RE_EOL)
RE_PROFILE_CAP = re.compile(RE_AUDIT_DENY + r'capability(?P<capability>(\s+\S+)+)?' + RE_COMMA_EOL)
RE_PROFILE_ALIAS = re.compile(r'^\s*alias\s+(?P<orig_path>"??.+?"??)\s+->\s*(?P<target>"??.+?"??)' + RE_COMMA_EOL)
RE_PROFILE_RLIMIT = re.compile(r'^\s*set\s+rlimit\s+(?P<rlimit>[a-z]+)\s*<=\s*(?P<value>[^ ]+(\s+[a-zA-Z]+)?)' + RE_COMMA_EOL)
RE_PROFILE_BOOLEAN = re.compile(r'^\s*(?P<varname>\$\{?\w*\}?)\s*=\s*(?P<value>true|false)\s*,?' + RE_EOL, flags=re.IGNORECASE)
RE_PROFILE_VARIABLE = re.compile(r'^\s*(?P<varname>@\{?\w+\}?)\s*(?P<mode>\+?=)\s*(?P<values>@*.+?)' + RE_EOL)
RE_PROFILE_CONDITIONAL = re.compile(r'^\s*if\s+(not\s+)?(\$\{?\w*\}?)\s*\{' + RE_EOL)
RE_PROFILE_CONDITIONAL_VARIABLE = re.compile(r'^\s*if\s+(not\s+)?defined\s+(@\{?\w+\}?)\s*\{\s*(#.*)?$')
RE_PROFILE_CONDITIONAL_BOOLEAN = re.compile(r'^\s*if\s+(not\s+)?defined\s+(\$\{?\w+\}?)\s*\{\s*(#.*)?$')
RE_PROFILE_NETWORK = re.compile(RE_AUDIT_DENY + r'network(?P<details>\s+.*)?' + RE_COMMA_EOL)
RE_PROFILE_CHANGE_HAT = re.compile(r'^\s*\^("??.+?"??)' + RE_COMMA_EOL)
RE_PROFILE_HAT_DEF = re.compile(r'^(?P<leadingspace>\s*)(?P<hat_keyword>\^|hat\s+)(?P<hat>"??[^)]+?"??)' + RE_FLAGS + r'\s*\{' + RE_EOL)
RE_PROFILE_DBUS = re.compile(RE_AUDIT_DENY + r'(dbus\s*,|dbus(?P<details>\s+[^#]*)\s*,)' + RE_EOL)
RE_PROFILE_MOUNT = re.compile(RE_AUDIT_DENY + r'((mount|remount|umount|unmount)(\s+[^#]*)?\s*,)' + RE_EOL)
RE_PROFILE_SIGNAL = re.compile(RE_AUDIT_DENY + r'(signal\s*,|signal(?P<details>\s+[^#]*)\s*,)' + RE_EOL)
RE_PROFILE_PTRACE = re.compile(RE_AUDIT_DENY + r'(ptrace\s*,|ptrace(?P<details>\s+[^#]*)\s*,)' + RE_EOL)
RE_PROFILE_PIVOT_ROOT = re.compile(RE_AUDIT_DENY + r'(pivot_root\s*,|pivot_root\s+[^#]*\s*,)' + RE_EOL)
RE_PROFILE_UNIX = re.compile(RE_AUDIT_DENY + r'(unix\s*,|unix\s+[^#]*\s*,)' + RE_EOL)
RE_PROFILE_USERNS = re.compile(RE_AUDIT_DENY + r'(userns\s*,|userns(?P<details>\s+[^#]*)\s*,)' + RE_EOL)
# match anything that's not " or #, or matching quotes with anything except quotes inside
__re_no_or_quoted_hash = '([^#"]|"[^"]*")*'
RE_RULE_HAS_COMMA = re.compile(
'^' + __re_no_or_quoted_hash
+ ',\s*(#.*)?$') # match comma plus any trailing comment
+ r',\s*(#.*)?$') # match comma plus any trailing comment
RE_HAS_COMMENT_SPLIT = re.compile(
'^(?P<not_comment>' + __re_no_or_quoted_hash + ')' # store in 'not_comment' group
+ '(?P<comment>#.*)$') # match trailing comment and store in 'comment' group
RE_PROFILE_START = re.compile(
'^(?P<leadingspace>\s*)'
r'^(?P<leadingspace>\s*)'
+ '('
+ RE_PROFILE_PATH_OR_VAR % 'plainprofile' # just a path
+ '|' # or
+ '(' + 'profile' + '\s+' + RE_PROFILE_NAME % 'namedprofile' + '(\s+' + RE_PROFILE_PATH_OR_VAR % 'attachment' + ')?' + ')' # 'profile', profile name, optionally attachment
+ '(' + 'profile' + r'\s+' + RE_PROFILE_NAME % 'namedprofile' + r'(\s+' + RE_PROFILE_PATH_OR_VAR % 'attachment' + ')?' + ')' # 'profile', profile name, optionally attachment
+ ')'
+ RE_XATTRS
+ RE_FLAGS
+ '\s*\{'
+ r'\s*\{'
+ RE_EOL)
RE_PROFILE_CHANGE_PROFILE = re.compile(
RE_AUDIT_DENY
+ 'change_profile'
+ '(\s+' + RE_SAFE_OR_UNSAFE + ')?' # optionally exec mode
+ '(\s+' + RE_PROFILE_PATH_OR_VAR % 'execcond' + ')?' # optionally exec condition
+ '(\s+->\s*' + RE_PROFILE_NAME % 'targetprofile' + ')?' # optionally '->' target profile
+ r'(\s+' + RE_SAFE_OR_UNSAFE + ')?' # optionally exec mode
+ r'(\s+' + RE_PROFILE_PATH_OR_VAR % 'execcond' + ')?' # optionally exec condition
+ r'(\s+->\s*' + RE_PROFILE_NAME % 'targetprofile' + ')?' # optionally '->' target profile
+ RE_COMMA_EOL)
@@ -92,22 +92,22 @@ RE_PATH_PERMS = '(?P<%s>[mrwalkPUCpucix]+)'
RE_PROFILE_FILE_ENTRY = re.compile(
RE_AUDIT_DENY
+ '(?P<owner>owner\s+)?' # optionally: <owner>
+ r'(?P<owner>owner\s+)?' # optionally: <owner>
+ '('
+ '(?P<bare_file>file)' # bare 'file,'
+ '|' # or
+ '(?P<file_keyword>file\s+)?' # optional 'file' keyword
+ r'(?P<file_keyword>file\s+)?' # optional 'file' keyword
+ '('
+ RE_PROFILE_PATH_OR_VAR % 'path' + '\s+' + RE_PATH_PERMS % 'perms' # path and perms
+ RE_PROFILE_PATH_OR_VAR % 'path' + r'\s+' + RE_PATH_PERMS % 'perms' # path and perms
+ '|' # or
+ RE_PATH_PERMS % 'perms2' + '\s+' + RE_PROFILE_PATH_OR_VAR % 'path2' # perms and path
+ RE_PATH_PERMS % 'perms2' + r'\s+' + RE_PROFILE_PATH_OR_VAR % 'path2' # perms and path
+ ')'
+ '(\s+->\s*' + RE_PROFILE_NAME % 'target' + ')?'
+ r'(\s+->\s*' + RE_PROFILE_NAME % 'target' + ')?'
+ '|' # or
+ '(?P<link_keyword>link\s+)' # 'link' keyword
+ '(?P<subset_keyword>subset\s+)?' # optional 'subset' keyword
+ r'(?P<link_keyword>link\s+)' # 'link' keyword
+ r'(?P<subset_keyword>subset\s+)?' # optional 'subset' keyword
+ RE_PROFILE_PATH_OR_VAR % 'link_path' # path
+ '\s+' + '->' + '\s+' # ' -> '
+ r'\s+' + '->' + r'\s+' # ' -> '
+ RE_PROFILE_PATH_OR_VAR % 'link_target' # path
+ ')'
+ RE_COMMA_EOL)
@@ -164,8 +164,8 @@ def parse_profile_start_line(line, filename):
RE_MAGIC_OR_QUOTED_PATH = '(<(?P<magicpath>.*)>|"(?P<quotedpath>.*)"|(?P<unquotedpath>[^<>"]*))'
RE_ABI = re.compile('^\s*#?abi\s*' + RE_MAGIC_OR_QUOTED_PATH + RE_COMMA_EOL)
RE_INCLUDE = re.compile('^\s*#?include(?P<ifexists>\s+if\s+exists)?\s*' + RE_MAGIC_OR_QUOTED_PATH + RE_EOL)
RE_ABI = re.compile(r'^\s*#?abi\s*' + RE_MAGIC_OR_QUOTED_PATH + RE_COMMA_EOL)
RE_INCLUDE = re.compile(r'^\s*#?include(?P<ifexists>\s+if\s+exists)?\s*' + RE_MAGIC_OR_QUOTED_PATH + RE_EOL)
def re_match_include_parse(line, rule_name):
@@ -196,7 +196,7 @@ def re_match_include_parse(line, rule_name):
ismagic = True
elif matches.group('unquotedpath'):
path = matches.group('unquotedpath').strip()
if re.search('\s', path):
if re.search(r'\s', path):
raise AppArmorException(_('Syntax error: %s must use quoted path or <...>') % rule_name)
# LP: #1738879 - parser doesn't handle unquoted paths everywhere
if rule_name == 'include':
@@ -212,7 +212,7 @@ def re_match_include_parse(line, rule_name):
raise AppArmorException(_('Syntax error: %s rule with empty filename') % rule_name)
# LP: #1738877 - parser doesn't handle files with spaces in the name
if rule_name == 'include' and re.search('\s', path):
if rule_name == 'include' and re.search(r'\s', path):
raise AppArmorException(_('Syntax error: %s rule filename cannot contain spaces') % rule_name)
ifexists = False

View File

@@ -27,43 +27,43 @@ message_keywords = ['send', 'receive', 'r', 'read', 'w', 'write', 'rw']
access_keywords = ['bind', 'eavesdrop'] + message_keywords
# XXX joint_access_keyword and RE_ACCESS_KEYWORDS exactly as in SignalRule - move to function?
joint_access_keyword = '(' + '(\s|,)*' + '(' + '|'.join(access_keywords) + ')(\s|,)*' + ')'
joint_access_keyword = '(' + r'(\s|,)*' + '(' + '|'.join(access_keywords) + r')(\s|,)*' + ')'
RE_ACCESS_KEYWORDS = (
joint_access_keyword # one of the access_keyword
+ '|' # or
+ '\(' + '(\s|,)*' + joint_access_keyword + '?' + '(' + '(\s|,)+' + joint_access_keyword + ')*' + '\)' # one or more access_keyword in (...)
+ r'\(' + r'(\s|,)*' + joint_access_keyword + '?' + '(' + r'(\s|,)+' + joint_access_keyword + ')*' + r'\)' # one or more access_keyword in (...)
)
RE_FLAG = '(?P<%s>(\S+|"[^"]+"|\(\s*\S+\s*\)|\(\s*"[^"]+"\)\s*))' # string without spaces, or quoted string, optionally wrapped in (...). %s is the match group name
RE_FLAG = r'(?P<%s>(\S+|"[^"]+"|\(\s*\S+\s*\)|\(\s*"[^"]+"\)\s*))' # string without spaces, or quoted string, optionally wrapped in (...). %s is the match group name
# plaintext version: | * | "* " | ( * ) | ( " * " ) |
# XXX this regex will allow repeated parameters, last one wins
# XXX (the parser will reject such rules)
RE_DBUS_DETAILS = re.compile(
'^'
+ '(\s+(?P<access>' + RE_ACCESS_KEYWORDS + '))?' # optional access keyword(s)
+ r'(\s+(?P<access>' + RE_ACCESS_KEYWORDS + '))?' # optional access keyword(s)
+ '('
+ '(\s+(bus\s*=\s*' + RE_FLAG % 'bus' + '))?|' # optional bus= system | session | AARE, (...) optional
+ '(\s+(path\s*=\s*' + RE_FLAG % 'path' + '))?|' # optional path=AARE, (...) optional
+ '(\s+(name\s*=\s*' + RE_FLAG % 'name' + '))?|' # optional name=AARE, (...) optional
+ '(\s+(interface\s*=\s*' + RE_FLAG % 'interface' + '))?|' # optional interface=AARE, (...) optional
+ '(\s+(member\s*=\s*' + RE_FLAG % 'member' + '))?|' # optional member=AARE, (...) optional
+ '(\s+(peer\s*=\s*\((,|\s)*' # optional peer=(name=AARE and/or label=AARE), (...) required
+ r'(\s+(bus\s*=\s*' + RE_FLAG % 'bus' + '))?|' # optional bus= system | session | AARE, (...) optional
+ r'(\s+(path\s*=\s*' + RE_FLAG % 'path' + '))?|' # optional path=AARE, (...) optional
+ r'(\s+(name\s*=\s*' + RE_FLAG % 'name' + '))?|' # optional name=AARE, (...) optional
+ r'(\s+(interface\s*=\s*' + RE_FLAG % 'interface' + '))?|' # optional interface=AARE, (...) optional
+ r'(\s+(member\s*=\s*' + RE_FLAG % 'member' + '))?|' # optional member=AARE, (...) optional
+ r'(\s+(peer\s*=\s*\((,|\s)*' # optional peer=(name=AARE and/or label=AARE), (...) required
+ '('
+ '(' + '(,|\s)*' + ')' # empty peer=()
+ '(' + r'(,|\s)*' + ')' # empty peer=()
+ '|' # or
+ '(' + 'name\s*=\s*' + RE_PROFILE_NAME % 'peername1' + ')' # only peer name (match group peername1)
+ '(' + r'name\s*=\s*' + RE_PROFILE_NAME % 'peername1' + ')' # only peer name (match group peername1)
+ '|' # or
+ '(' 'label\s*=\s*' + RE_PROFILE_NAME % 'peerlabel1' + ')' # only peer label (match group peerlabel1)
+ '(' r'label\s*=\s*' + RE_PROFILE_NAME % 'peerlabel1' + ')' # only peer label (match group peerlabel1)
+ '|' # or
+ '(' + 'name\s*=\s*' + RE_PROFILE_NAME % 'peername2' + '(,|\s)+' + 'label\s*=\s*' + RE_PROFILE_NAME % 'peerlabel2' + ')' # peer name + label (match name peername2/peerlabel2)
+ '(' + r'name\s*=\s*' + RE_PROFILE_NAME % 'peername2' + r'(,|\s)+' + r'label\s*=\s*' + RE_PROFILE_NAME % 'peerlabel2' + ')' # peer name + label (match name peername2/peerlabel2)
+ '|' # or
+ '(' + 'label\s*=\s*' + RE_PROFILE_NAME % 'peerlabel3' + '(,|\s)+' + 'name\s*=\s*' + RE_PROFILE_NAME % 'peername3' + ')' # peer label + name (match name peername3/peerlabel3)
+ '(' + r'label\s*=\s*' + RE_PROFILE_NAME % 'peerlabel3' + r'(,|\s)+' + r'name\s*=\s*' + RE_PROFILE_NAME % 'peername3' + ')' # peer label + name (match name peername3/peerlabel3)
+ ')'
+ '(,|\s)*\)))?'
+ r'(,|\s)*\)))?'
+ '){0,6}'
+ '\s*$')
+ r'\s*$')
class DbusRule(BaseRule):
@@ -80,7 +80,7 @@ class DbusRule(BaseRule):
_match_re = RE_PROFILE_DBUS
def __init__(self, access, bus, path, name, interface, member, peername, peerlabel,
audit=False, deny=False, allow_keyword=False, comment='', log_event=None):
audit=False, deny=False, allow_keyword=False, comment='', log_event=None):
super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword,
comment=comment, log_event=log_event)

View File

@@ -37,10 +37,10 @@ RE_NETWORK_TYPE = '(' + '|'.join(network_type_keywords) + ')'
RE_NETWORK_PROTOCOL = '(' + '|'.join(network_protocol_keywords) + ')'
RE_NETWORK_DETAILS = re.compile(
'^\s*'
r'^\s*'
+ '(?P<domain>' + RE_NETWORK_DOMAIN + ')?' # optional domain
+ '(\s+(?P<type_or_protocol>' + RE_NETWORK_TYPE + '|' + RE_NETWORK_PROTOCOL + '))?' # optional type or protocol
+ '\s*$')
+ r'(\s+(?P<type_or_protocol>' + RE_NETWORK_TYPE + '|' + RE_NETWORK_PROTOCOL + '))?' # optional type or protocol
+ r'\s*$')
class NetworkRule(BaseRule):

View File

@@ -26,17 +26,17 @@ _ = init_translation()
access_keywords = ['r', 'w', 'rw', 'wr', 'read', 'write', 'readby', 'trace', 'tracedby'] # XXX 'wr' and 'write' accepted by the parser, but not documented in apparmor.d.pod
# XXX joint_access_keyword and RE_ACCESS_KEYWORDS exactly as in PtraceRule - move to function!
joint_access_keyword = '\s*(' + '|'.join(access_keywords) + ')\s*'
joint_access_keyword = r'\s*(' + '|'.join(access_keywords) + r')\s*'
RE_ACCESS_KEYWORDS = (joint_access_keyword # one of the access_keyword
+ '|' # or
+ '\(' + joint_access_keyword + '(' + '(\s|,)+' + joint_access_keyword + ')*' + '\)') # one or more access_keyword in (...)
+ r'\(' + joint_access_keyword + '(' + r'(\s|,)+' + joint_access_keyword + ')*' + r'\)') # one or more access_keyword in (...)
RE_PTRACE_DETAILS = re.compile(
'^'
+ '(\s+(?P<access>' + RE_ACCESS_KEYWORDS + '))?' # optional access keyword(s)
+ '(\s+(peer=' + RE_PROFILE_NAME % 'peer' + '))?' # optional peer
+ '\s*$')
+ r'(\s+(?P<access>' + RE_ACCESS_KEYWORDS + '))?' # optional access keyword(s)
+ r'(\s+(peer=' + RE_PROFILE_NAME % 'peer' + '))?' # optional peer
+ r'\s*$')
class PtraceRule(BaseRule):

View File

@@ -29,9 +29,9 @@ rlimit_nice = ['nice'] # a number between -20 and 19.
rlimit_all = rlimit_size + rlimit_number + rlimit_time + rlimit_nice
RE_NUMBER_UNIT = re.compile('^(?P<number>[0-9]+)\s*(?P<unit>[a-zA-Z]*)$')
RE_NUMBER_UNIT = re.compile(r'^(?P<number>[0-9]+)\s*(?P<unit>[a-zA-Z]*)$')
RE_NUMBER = re.compile('^[0-9]+$')
RE_UNIT_SIZE = re.compile('^[0-9]+\s*([KMG]B?)?$')
RE_UNIT_SIZE = re.compile(r'^[0-9]+\s*([KMG]B?)?$')
RE_NICE = re.compile('^(-20|-[01]?[0-9]|[01]?[0-9])$')

View File

@@ -33,34 +33,34 @@ signal_keywords = [
'segv', 'usr2', 'pipe', 'alrm', 'term', 'stkflt', 'chld', 'cont', 'stop',
'stp', 'ttin', 'ttou', 'urg', 'xcpu', 'xfsz', 'vtalrm', 'prof', 'winch',
'io', 'pwr', 'sys', 'emt', 'exists']
RE_SIGNAL_REALTIME = re.compile('^rtmin\+0*([0-9]|[12][0-9]|3[0-2])$') # rtmin+0..rtmin+32, number may have leading zeros
RE_SIGNAL_REALTIME = re.compile(r'^rtmin\+0*([0-9]|[12][0-9]|3[0-2])$') # rtmin+0..rtmin+32, number may have leading zeros
joint_access_keyword = '\s*(' + '|'.join(access_keywords) + ')\s*'
joint_access_keyword = r'\s*(' + '|'.join(access_keywords) + r')\s*'
RE_ACCESS_KEYWORDS = (
joint_access_keyword # one of the access_keyword
+ '|' # or
+ '\(' + joint_access_keyword + '(' + '(\s|,)+' + joint_access_keyword + ')*' + '\)' # one or more access_keyword in (...)
+ r'\(' + joint_access_keyword + '(' + r'(\s|,)+' + joint_access_keyword + ')*' + r'\)' # one or more access_keyword in (...)
)
signal_keyword = '\s*([a-z0-9+]+|"[a-z0-9+]+")\s*' # don't check against the signal keyword list in the regex to allow a more helpful error message
signal_keyword = r'\s*([a-z0-9+]+|"[a-z0-9+]+")\s*' # don't check against the signal keyword list in the regex to allow a more helpful error message
RE_SIGNAL_KEYWORDS = (
'set\s*=\s*' + signal_keyword # one of the signal_keyword
r'set\s*=\s*' + signal_keyword # one of the signal_keyword
+ '|' # or
+ 'set\s*=\s*\(' + signal_keyword + '(' + '(\s|,)+' + signal_keyword + ')*' + '\)' # one or more signal_keyword in (...)
+ r'set\s*=\s*\(' + signal_keyword + '(' + r'(\s|,)+' + signal_keyword + ')*' + r'\)' # one or more signal_keyword in (...)
)
RE_SIGNAL_DETAILS = re.compile(
'^'
+ '(\s+(?P<access>' + RE_ACCESS_KEYWORDS + '))?' # optional access keyword(s)
+ '(?P<signal>' + '(\s+(' + RE_SIGNAL_KEYWORDS + '))+' + ')?' # optional signal set(s)
+ '(\s+(peer=' + RE_PROFILE_NAME % 'peer' + '))?' # optional peer
+ '\s*$')
+ r'(\s+(?P<access>' + RE_ACCESS_KEYWORDS + '))?' # optional access keyword(s)
+ '(?P<signal>' + r'(\s+(' + RE_SIGNAL_KEYWORDS + '))+' + ')?' # optional signal set(s)
+ r'(\s+(peer=' + RE_PROFILE_NAME % 'peer' + '))?' # optional peer
+ r'\s*$')
RE_FILTER_SET_1 = re.compile('set\s*=\s*\(([^)]*)\)')
RE_FILTER_SET_2 = re.compile('set\s*=')
RE_FILTER_PARENTHESIS = re.compile('\((.*)\)')
RE_FILTER_SET_1 = re.compile(r'set\s*=\s*\(([^)]*)\)')
RE_FILTER_SET_2 = re.compile(r'set\s*=')
RE_FILTER_PARENTHESIS = re.compile(r'\((.*)\)')
RE_FILTER_QUOTES = re.compile('"([a-z0-9]+)"') # used to strip quotes around signal keywords - don't use for peer!

View File

@@ -165,7 +165,7 @@ def separate_vars(vs):
data = set()
vs = vs.strip()
re_vars = re.compile('^(("[^"]*")|([^"\s]+))\s*(.*)$')
re_vars = re.compile(r'^(("[^"]*")|([^"\s]+))\s*(.*)$')
while re_vars.search(vs):
matches = re_vars.search(vs).groups()

View File

@@ -108,8 +108,8 @@ def get_translated_hotkey(translated, cmsg=''):
msg = 'PromptUser: ' + _('Invalid hotkey for')
# Originally (\S) was used but with translations it would not work :(
if re.search('\((\S+)\)', translated):
return re.search('\((\S+)\)', translated).groups()[0]
if re.search(r'\((\S+)\)', translated):
return re.search(r'\((\S+)\)', translated).groups()[0]
else:
if cmsg:
raise AppArmorException(cmsg)
@@ -439,7 +439,7 @@ class PromptQuestion:
function_regexp = '^('
function_regexp += '|'.join(keys.keys())
if options:
function_regexp += '|\d'
function_regexp += r'|\d'
function_regexp += ')$'
ans = 'XXXINVALIDXXX'
@@ -511,7 +511,7 @@ class PromptQuestion:
# If they hit return choose default option
ans = default_key
elif options and re.search('^\d$', ans):
elif options and re.search(r'^\d$', ans):
ans = int(ans)
if ans > 0 and ans <= len(options):
selected = ans - 1

View File

@@ -162,9 +162,9 @@ type=AVC msg=audit(1348982148.195:2933): apparmor="DENIED" operation="file_lock"
self._run_file_test(content, expected_strings)
def test_simple_embedded_backslash_carat(self):
"""test simple decoding of embedded \^ in files"""
r"""test simple decoding of embedded \^ in files"""
expected_strings = ('name="/home/steve/tmp/my test \^file"',)
expected_strings = (r'name="/home/steve/tmp/my test \^file"',)
content = \
'''type=AVC msg=audit(1349805073.402:6857): apparmor="DENIED" operation="mknod" parent=5890 profile="/usr/bin/test_profile" name=2F686F6D652F73746576652F746D702F6D792074657374205C5E66696C65 pid=5891 comm="touch" requested_mask="c" denied_mask="c" fsuid=1000 ouid=1000
'''

View File

@@ -2597,7 +2597,7 @@ POLICYGROUPS_DIR="%s/templates"
'foo<',
'foo>',
'foo?',
'foo\/',
r'foo\/',
'foo,',
'_foo',
]

View File

@@ -21,17 +21,17 @@ from common_test import AATest, setup_all_loops
class TestConvert_regexp(AATest):
tests = (
('/foo', '^/foo$'),
('/{foo,bar}', '^/(foo|bar)$'),
# ('/\{foo,bar}', '^/\{foo,bar}$'), # XXX gets converted to ^/\(foo|bar)$
('/fo[abc]', '^/fo[abc]$'),
('/foo bar', '^/foo bar$'),
('/x\y', '^/x\y$'),
('/x\[y', '^/x\[y$'),
('/x\\y', '^/x\\y$'),
('/fo?', '^/fo[^/\000]$'),
('/foo/*', '^/foo/(((?<=/)[^/\000]+)|((?<!/)[^/\000]*))$'),
('/foo/**.bar', '^/foo/(((?<=/)[^\000]+)|((?<!/)[^\000]*))\.bar$'),
('/foo', '^/foo$'),
('/{foo,bar}', '^/(foo|bar)$'),
# ('/\{foo,bar}', '^/\{foo,bar}$'), # XXX gets converted to ^/\(foo|bar)$
('/fo[abc]', '^/fo[abc]$'),
('/foo bar', '^/foo bar$'),
(r'/x\y', r'^/x\y$'),
(r'/x\[y', r'^/x\[y$'),
('/x\\y', '^/x\\y$'),
('/fo?', '^/fo[^/\000]$'),
('/foo/*', '^/foo/(((?<=/)[^/\000]+)|((?<!/)[^/\000]*))$'),
('/foo/**.bar', '^/foo/(((?<=/)[^\000]+)|((?<!/)[^\000]*))\\.bar$'),
)
def _run_test(self, params, expected):

View File

@@ -66,7 +66,7 @@ class TestBaserule(AATest):
self.ValidSubclass.match('foo')
def test_parse_modifiers_invalid(self):
regex = re.compile('^\s*(?P<audit>audit\s+)?(?P<allow>allow\s+|deny\s+|invalid\s+)?')
regex = re.compile(r'^\s*(?P<audit>audit\s+)?(?P<allow>allow\s+|deny\s+|invalid\s+)?')
matches = regex.search('audit invalid ')
with self.assertRaises(AppArmorBug):