[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