[apparmor] [patch 1/2] add and use parse_profile_start_line()

Christian Boltz apparmor at cboltz.de
Wed Mar 4 21:40:40 UTC 2015


Hello,

this patch adds the parse_profile_start_line() function to regex.py,
which is a wrapper for RE_PROFILE_START_2 and returns an array with
named matches.

It also changes some places in aa.py from using RE_PROFILE_START to the
parse_profile_start_line() function.

Notes:
- until everything is migrated to the new function, I'll keep the old 
  RE_PROFILE_START unchanged - that's the reason to add the new regex
  as RE_PROFILE_START_2
- the patch changes only aa.py sections that are covered by tests already
  (which means some users of RE_PROFILE_START are remaining)
- parse_profile_start_line() merges 'profile' and 'attachment' into 
  'profile' (aka the old, broken behaviour) until aa.py can handle the 
  attachment properly. The alternative would be to ignore 'attachment', 
  which would be worse.

I propose this patch for trunk and 2.9.


[ add-and-use-parse_profile_start_line.diff ]

=== modified file 'utils/apparmor/aa.py'
--- utils/apparmor/aa.py        2015-03-03 19:15:00 +0000
+++ utils/apparmor/aa.py        2015-03-04 20:45:29 +0000
@@ -49,7 +49,7 @@
                             RE_PROFILE_HAT_DEF, RE_PROFILE_DBUS, RE_PROFILE_MOUNT,
                             RE_PROFILE_SIGNAL, RE_PROFILE_PTRACE, RE_PROFILE_PIVOT_ROOT,
                             RE_PROFILE_UNIX, RE_RULE_HAS_COMMA, RE_HAS_COMMENT_SPLIT,
-                            strip_quotes )
+                            strip_quotes, parse_profile_start_line )
 
 import apparmor.rules as aarules
 
@@ -613,11 +613,9 @@
     with open_file_read(filename) as f_in:
         for line in f_in:
             if RE_PROFILE_START.search(line):
-                matches = RE_PROFILE_START.search(line).groups()
-                profile = matches[1] or matches[3]
-                flags = matches[6]
-                if flags and flags.strip() == '':
-                    raise AppArmorException(_('Invalid syntax in %(filename)s for profile %(profile)s: Empty set of flags.' % { 'filename': filename, 'profile': profile } ))
+                matches = parse_profile_start_line(line, filename)
+                profile = matches['profile']
+                flags = matches['flags']
                 if profile == program or program is None:
                     return flags
 
@@ -2637,26 +2645,23 @@
 
 
 def parse_profile_start(line, file, lineno, profile, hat):
-    matches = RE_PROFILE_START.search(line).groups()
+    matches = parse_profile_start_line(line, file)
 
     pps_set_profile = False
     pps_set_hat_external = False
 
     if profile:
         #print(profile, hat)
-        if profile != hat or not matches[3]:
+        if profile != hat or not matches['profile_keyword']:
             raise AppArmorException(_('%(profile)s profile in %(file)s contains syntax errors in line: %(line)s.') % { 'profile': profile, 'file': file, 'line': lineno + 1 })
     # Keep track of the start of a profile
-    if profile and profile == hat and matches[3]:
+    if profile and profile == hat and matches['profile_keyword']:
         # local profile
-        hat = matches[3]
+        hat = matches['profile']
         in_contained_hat = True
         pps_set_profile = True
     else:
-        if matches[1]:
-            profile = matches[1]
-        else:
-            profile = matches[3]
+        profile = matches['profile']
         #print(profile)
         if len(profile.split('//')) >= 2:
             profile, hat = profile.split('//')[:2]
@@ -2668,11 +2673,7 @@
         else:
             hat = profile
 
-    flags = matches[6]
-
-    profile = strip_quotes(profile)
-    if hat:
-        hat = strip_quotes(hat)
+    flags = matches['flags']
 
     return (profile, hat, flags, in_contained_hat, pps_set_profile, pps_set_hat_external)
 

=== modified file 'utils/apparmor/regex.py'
--- utils/apparmor/regex.py     2015-03-03 19:15:00 +0000
+++ utils/apparmor/regex.py     2015-03-04 20:56:07 +0000
@@ -14,6 +14,11 @@
 # ----------------------------------------------------------------------
 
 import re
+from apparmor.common import AppArmorBug, AppArmorException
+
+# setup module translations
+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
@@ -56,6 +62,52 @@
     '(?P<comment>#.*)$')  # match trailing comment and store in 'comment' group
 
 
+
+RE_PROFILE_START_2        = re.compile(
+    '^(?P<leadingspace>\s*)' +
+    '(' +
+        '(?P<plainprofile>(/\S+|"[^"]+"))' + # just a path
+        '|' + # or
+        '(' + 'profile' + '\s+(?P<namedprofile>(\S+|"[^"]+"))' + '(\s+(?P<attachment>(/\S+|"/[^"]+")))?' + ')' + # 'profile', profile name, optionally attachment
+    ')' +
+    '\s+((flags=)?\((?P<flags>.+)\)\s+)?\{' +
+    RE_EOL)
+
+def parse_profile_start_line(line, filename):
+    matches = RE_PROFILE_START_2.search(line)
+
+    if not matches:
+        raise AppArmorBug('The given line from file %(filename)s is not the start of a profile: %(line)s' % { 'filename': filename, 'line': line } )
+
+    result = {}
+
+    for section in [ 'leadingspace', 'plainprofile', 'namedprofile', 'attachment', 'flags', 'comment']:
+        if matches.group(section):
+            result[section] = matches.group(section)
+
+            # sections with optional quotes
+            if section in ['plainprofile', 'namedprofile', 'attachment']:
+                result[section] = strip_quotes(result[section])
+        else:
+            result[section] = None
+
+    if result['flags'] and result['flags'].strip() == '':
+        raise AppArmorException(_('Invalid syntax in %(filename)s: Empty set of flags in line %(line)s.' % { 'filename': filename, 'line': line } ))
+
+    if result['plainprofile']:
+        result['profile'] = result['plainprofile']
+        result['profile_keyword'] = False
+    else:
+        result['profile'] = result['namedprofile']
+        result['profile_keyword'] = True
+
+    if result['attachment']:
+        # XXX keep the broken behaviour until proper handling for attachment is implemented
+        result['profile'] = "%s %s" % (result['profile'], result['attachment'])
+
+    return result
+
+
 def strip_quotes(data):
     if data[0] + data[-1] == '""':
         return data[1:-1]



Regards,

Christian Boltz
-- 
> > Gruß,
> > Jörg
> Huch? Wo ist denn Ratti hingekommen? ;-)
Das ist eine sehr gute Frage... ich weiss auch nicht...
[> Christian Boltz und (>>) Ratti in fontlinge-devel]




More information about the AppArmor mailing list