[apparmor] [PATCH 3/3] utils: Basic support for pivot_root rules

Tyler Hicks tyhicks at canonical.com
Fri Apr 4 18:28:20 UTC 2014


On 2014-04-04 11:17:17, Steve Beattie wrote:
> On Thu, Apr 03, 2014 at 02:56:01PM -0500, Tyler Hicks wrote:
> > Bug: https://bugs.launchpad.net/bugs/1298678
> > 
> > This patch does bare bones parsing of pivot_root rules and stores the raw
> > strings for writing them out later. It is meant to be a simple change to
> > prevent aa.py from emitting a traceback when encountering pivot_root rules.
> > 
> > Signed-off-by: Tyler Hicks <tyhicks at canonical.com>
> 
> A meta question: do we see the pivot_root policy statements as a
> significantly different class of rules from the rest of the mount
> rules to be worth handling them separately? (I'm unfortunately not
> as familiar with the intricacies of those classes of rules.)

I can't say that I'm very familiar with them, either. But they do seem
different enough that we would handle them differently.

mount rules have fstypes, mount options, and the '->' symbol is used to
point to the destination mount point.

pivot_root rules don't have variables such as fstype or mount options
and the '->' symbol is used to point to another profile to change to
when pivoting.

I say that they should be treated differently, but we probably need JJ
to weigh in.

What do you say, John?

Tyler

> 
> > ---
> >  utils/apparmor/aa.py                | 49 +++++++++++++++++++++++
> >  utils/apparmor/rules.py             | 12 ++++++
> >  utils/test/test-pivot_root_parse.py | 36 +++++++++++++++++
> >  utils/test/test-regex_matches.py    | 79 +++++++++++++++++++++++++++++++++++++
> >  4 files changed, 176 insertions(+)
> >  create mode 100644 utils/test/test-pivot_root_parse.py
> > 
> > diff --git a/utils/apparmor/aa.py b/utils/apparmor/aa.py
> > index 8c1e374..a2971c3 100644
> > --- a/utils/apparmor/aa.py
> > +++ b/utils/apparmor/aa.py
> > @@ -2626,6 +2626,7 @@ RE_PROFILE_DBUS = re.compile('^\s*(audit\s+)?(allow\s+|deny\s+)?(dbus[^#]*\s*,)\
> >  RE_PROFILE_MOUNT = re.compile('^\s*(audit\s+)?(allow\s+|deny\s+)?((mount|remount|umount)[^#]*\s*,)\s*(#.*)?$')
> >  RE_PROFILE_SIGNAL = re.compile('^\s*(audit\s+)?(allow\s+|deny\s+)?((signal)[^#]*\s*,)\s*(#.*)?$')
> >  RE_PROFILE_PTRACE = re.compile('^\s*(audit\s+)?(allow\s+|deny\s+)?((ptrace)[^#]*\s*,)\s*(#.*)?$')
> > +RE_PROFILE_PIVOT_ROOT = re.compile('^\s*(audit\s+)?(allow\s+|deny\s+)?((pivot_root)[^#]*\s*,)\s*(#.*)?$')
> >  
> >  # match anything that's not " or #, or matching quotes with anything except quotes inside
> >  __re_no_or_quoted_hash = '([^#"]|"[^"]*")*'
> > @@ -2706,6 +2707,7 @@ def parse_profile_data(data, file, do_include):
> >              profile_data[profile][hat]['allow']['mount'] = list()
> >              profile_data[profile][hat]['allow']['signal'] = list()
> >              profile_data[profile][hat]['allow']['ptrace'] = list()
> > +            profile_data[profile][hat]['allow']['pivot_root'] = list()
> >              # Save the initial comment
> >              if initial_comment:
> >                  profile_data[profile][hat]['initial_comment'] = initial_comment
> > @@ -3110,6 +3112,28 @@ def parse_profile_data(data, file, do_include):
> >              ptrace_rules.append(ptrace_rule)
> >              profile_data[profile][hat][allow]['ptrace'] = ptrace_rules
> >  
> > +        elif RE_PROFILE_PIVOT_ROOT.search(line):
> > +            matches = RE_PROFILE_PIVOT_ROOT.search(line).groups()
> > +
> > +            if not profile:
> > +                raise AppArmorException(_('Syntax Error: Unexpected ptrace entry found in file: %s line: %s') % (file, lineno + 1))
> 
> s/ptrace/pivot_root/ here
> 
> > +
> > +            audit = False
> > +            if matches[0]:
> > +                audit = True
> > +            allow = 'allow'
> > +            if matches[1] and matches[1].strip() == 'deny':
> > +                allow = 'deny'
> > +            pivot_root = matches[2].strip()
> > +
> > +            pivot_root_rule = parse_pivot_root_rule(pivot_root)
> > +            pivot_root_rule.audit = audit
> > +            pivot_root_rule.deny = (allow == 'deny')
> > +
> > +            pivot_root_rules = profile_data[profile][hat][allow].get('pivot_root', list())
> > +            pivot_root_rules.append(pivot_root_rule)
> > +            profile_data[profile][hat][allow]['pivot_root'] = pivot_root_rules
> > +
> >          elif RE_PROFILE_CHANGE_HAT.search(line):
> >              matches = RE_PROFILE_CHANGE_HAT.search(line).groups()
> >  
> > @@ -3216,6 +3240,10 @@ def parse_ptrace_rule(line):
> >      # XXX Do real parsing here
> >      return aarules.Raw_Ptrace_Rule(line)
> >  
> > +def parse_pivot_root_rule(line):
> > +    # XXX Do real parsing here
> > +    return aarules.Raw_Pivot_Root_Rule(line)
> > +
> >  def separate_vars(vs):
> >      """Returns a list of all the values for a variable"""
> >      data = []
> > @@ -3481,6 +3509,24 @@ def write_ptrace(prof_data, depth):
> >      data += write_ptrace_rules(prof_data, depth, 'allow')
> >      return data
> >  
> > +def write_pivot_root_rules(prof_data, depth, allow):
> > +    pre = '  ' * depth
> > +    data = []
> > +
> > +    # no pivot_root rules, so return
> > +    if not prof_data[allow].get('pivot_root', False):
> > +        return data
> > +
> > +    for pivot_root_rule in prof_data[allow]['pivot_root']:
> > +        data.append('%s%s' % (pre, pivot_root_rule.serialize()))
> > +    data.append('')
> > +    return data
> > +
> > +def write_pivot_root(prof_data, depth):
> > +    data = write_pivot_root_rules(prof_data, depth, 'deny')
> > +    data += write_pivot_root_rules(prof_data, depth, 'allow')
> > +    return data
> > +
> >  def write_link_rules(prof_data, depth, allow):
> >      pre = '  ' * depth
> >      data = []
> > @@ -3589,6 +3635,7 @@ def write_rules(prof_data, depth):
> >      data += write_mount(prof_data, depth)
> >      data += write_signal(prof_data, depth)
> >      data += write_ptrace(prof_data, depth)
> > +    data += write_pivot_root(prof_data, depth)
> >      data += write_links(prof_data, depth)
> >      data += write_paths(prof_data, depth)
> >      data += write_change_profile(prof_data, depth)
> > @@ -3740,6 +3787,7 @@ def serialize_profile_from_old_profile(profile_data, name, options):
> >                           'mount': write_mount,
> >                           'signal': write_signal,
> >                           'ptrace': write_ptrace,
> > +                         'pivot_root': write_pivot_root,
> >                           'link': write_links,
> >                           'path': write_paths,
> >                           'change_profile': write_change_profile,
> > @@ -3834,6 +3882,7 @@ def serialize_profile_from_old_profile(profile_data, name, options):
> >                      data += write_mount(write_prof_data[name], depth)
> >                      data += write_signal(write_prof_data[name], depth)
> >                      data += write_ptrace(write_prof_data[name], depth)
> > +                    data += write_pivot_root(write_prof_data[name], depth)
> >                      data += write_links(write_prof_data[name], depth)
> >                      data += write_paths(write_prof_data[name], depth)
> >                      data += write_change_profile(write_prof_data[name], depth)
> > diff --git a/utils/apparmor/rules.py b/utils/apparmor/rules.py
> > index 5b93e1e..36640f3 100644
> > --- a/utils/apparmor/rules.py
> > +++ b/utils/apparmor/rules.py
> > @@ -91,3 +91,15 @@ class Raw_Ptrace_Rule(object):
> >          return "%s%s%s" % ('audit ' if self.audit else '',
> >                             'deny '  if self.deny else '',
> >                             self.rule)
> > +
> > +class Raw_Pivot_Root_Rule(object):
> > +    audit = False
> > +    deny = False
> > +
> > +    def __init__(self, rule):
> > +        self.rule = rule
> > +
> > +    def serialize(self):
> > +        return "%s%s%s" % ('audit ' if self.audit else '',
> > +                           'deny '  if self.deny else '',
> > +                           self.rule)
> > diff --git a/utils/test/test-pivot_root_parse.py b/utils/test/test-pivot_root_parse.py
> > new file mode 100644
> > index 0000000..7b40f71
> > --- /dev/null
> > +++ b/utils/test/test-pivot_root_parse.py
> > @@ -0,0 +1,36 @@
> > +#! /usr/bin/env python
> > +# ------------------------------------------------------------------
> > +#
> > +#    Copyright (C) 2014 Canonical Ltd.
> > +#
> > +#    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 apparmor.aa as aa
> > +import unittest
> > +
> > +class AAParsePivotRootTest(unittest.TestCase):
> > +
> > +    def _test_parse_pivot_root_rule(self, rule):
> > +        pivot_root = aa.parse_pivot_root_rule(rule)
> > +        print(pivot_root.serialize())
> 
> Same nit as before here.
> 
> > +        self.assertEqual(rule, pivot_root.serialize(),
> > +                'pivot_root object returned "%s", expected "%s"' % (pivot_root.serialize(), rule))
> > +
> > +    def test_parse_plain_pivot_root_rule(self):
> > +        self._test_parse_pivot_root_rule('pivot_root,')
> > +
> > +    def test_parse_old_pivot_root_rule(self):
> > +        self._test_parse_pivot_root_rule('pivot_root /old,')
> > +
> > +    def test_parse_new_pivot_root_rule(self):
> > +        self._test_parse_pivot_root_rule('pivot_root /old /new,')
> > +
> > +    def test_parse_child_pivot_root_rule(self):
> > +        self._test_parse_pivot_root_rule('pivot_root /old /new -> /usr/bin/child,')
> > +
> > +if __name__ == '__main__':
> > +    unittest.main()
> 
> -- 
> Steve Beattie
> <sbeattie at ubuntu.com>
> http://NxNW.org/~steve/



> -- 
> AppArmor mailing list
> AppArmor at lists.ubuntu.com
> Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <https://lists.ubuntu.com/archives/apparmor/attachments/20140404/f2dce217/attachment-0001.pgp>


More information about the AppArmor mailing list