]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
add rootwrap filters to wrap ip netns exec
authorMark McClain <mark.mcclain@dreamhost.com>
Tue, 4 Sep 2012 23:50:00 +0000 (19:50 -0400)
committerMark McClain <mark.mcclain@dreamhost.com>
Wed, 5 Sep 2012 02:25:34 +0000 (22:25 -0400)
fixes bug 1044083

This patch adds specific filters for the ip command. The first filter
matches ip with any subcomand except netns exec.  The second filter
matches "ip netns exec" and then relies on the caller (match_filter) to
verify the sub-command against the other filters. Matching the
subcommand separately allows for a single set of filter definitions that
work with and without namespaces.

Change-Id: Ifd0378dc3461f84867efb3cb60396d9cfa9e582d

etc/quantum/rootwrap.d/dhcp.filters
etc/quantum/rootwrap.d/l3.filters
etc/quantum/rootwrap.d/linuxbridge-plugin.filters
quantum/rootwrap/filters.py
quantum/rootwrap/wrapper.py
quantum/tests/unit/test_rootwrap.py

index 7a9fa8a444de933bbc52902a4eea0d8a5f52995b..09204ad0a17767dd533133dee173b132190cb80a 100644 (file)
@@ -20,3 +20,9 @@ kill_dnsmasq_usr: KillFilter, root, /usr/sbin/dnsmasq, -9, -HUP
 
 # dhcp-agent uses cat
 cat: RegExpFilter, /bin/cat, root, cat, /proc/\d+/cmdline
+
+# ip_lib
+ip: IpFilter, /sbin/ip, root
+ip_usr: IpFilter, /usr/sbin/ip, root
+ip_exec: IpNetnsExecFilter, /sbin/ip, root
+ip_exec_usr: IpNetnsExecFilter, /usr/sbin/ip, root
index e471217dc6c9a5b60842b9e37f990a34a6bdbd15..5a7be352b0d0b6d01a36474f5859a76d304f48d6 100644 (file)
 sysctl: CommandFilter, /sbin/sysctl, root
 
 # ip_lib
-ip: CommandFilter, /sbin/ip, root
-ip_usr: CommandFilter, /usr/sbin/ip, root
+ip: IpFilter, /sbin/ip, root
+ip_usr: IpFilter, /usr/sbin/ip, root
+ip_exec: IpNetnsExecFilter, /sbin/ip, root
+ip_exec_usr: IpNetnsExecFilter, /usr/sbin/ip, root
 
 # ovs_lib (if OVSInterfaceDriver is used)
 ovs-vsctl: CommandFilter, /bin/ovs-vsctl, root
index 591f69e4f6e7b77d0a1e7845677422aef19139fa..301280cb03b99a34c2ccff1120298278798528f1 100644 (file)
@@ -13,5 +13,9 @@
 # from the old mechanism
 brctl: CommandFilter, /sbin/brctl, root
 brctl_usr: CommandFilter, /usr/sbin/brctl, root
-ip: CommandFilter, /sbin/ip, root
-ip_usr: CommandFilter, /usr/sbin/ip, root
+
+# ip_lib
+ip: IpFilter, /sbin/ip, root
+ip_usr: IpFilter, /usr/sbin/ip, root
+ip_exec: IpNetnsExecFilter, /sbin/ip, root
+ip_exec_usr: IpNetnsExecFilter, /usr/sbin/ip, root
index 8b3b89ba2c2539a8c14953850a9974f73ee67761..189ab7a20bc72326473b4dd3a4fb7b83db511dbc 100644 (file)
@@ -44,6 +44,11 @@ class CommandFilter(object):
         return None
 
 
+class ExecCommandFilter(CommandFilter):
+    def exec_args(self, userargs):
+        return []
+
+
 class RegExpFilter(CommandFilter):
     """Command filter doing regexp matching for every argument"""
 
@@ -163,3 +168,29 @@ class ReadFileFilter(CommandFilter):
         if len(userargs) != 2:
             return False
         return True
+
+
+class IpFilter(CommandFilter):
+    """Specific filter for the ip utility to that does not match exec."""
+
+    def match(self, userargs):
+        if userargs[0] == 'ip':
+            if userargs[1] == 'netns':
+                if userargs[2] in ('list', 'add', 'delete'):
+                    return True
+                else:
+                    return False
+            else:
+                return True
+
+
+class IpNetnsExecFilter(ExecCommandFilter):
+    """Specific filter for the ip utility to that does match exec."""
+    def match(self, userargs):
+        if userargs[:3] == ['ip', 'netns', 'exec']:
+            return True
+        else:
+            return False
+
+    def exec_args(self, userargs):
+        return userargs[4:]
index 58b45bbc79921b62068f308b9557eb7d7c79edaf..4d44d1776b4b9bf0dbb146a598f07fb0fd918191 100644 (file)
@@ -54,7 +54,7 @@ def load_filters(filters_path):
     return filterlist
 
 
-def match_filter(filters, userargs):
+def match_filter(filter_list, userargs):
     """
     Checks user command and arguments through command filters and
     returns the first matching filter, or None is none matched.
@@ -62,8 +62,18 @@ def match_filter(filters, userargs):
 
     found_filter = None
 
-    for f in filters:
+    for f in filter_list:
         if f.match(userargs):
+            if isinstance(f, filters.ExecCommandFilter):
+                # This command calls exec verify that remaining args
+                # matches another filter.
+                leaf_filters = [fltr for fltr in filter_list
+                                if not isinstance(fltr,
+                                                  filters.ExecCommandFilter)]
+                args = f.exec_args(userargs)
+                if not args or not match_filter(leaf_filters, args):
+                    continue
+
             # Try other filters if executable is absent
             if not os.access(f.exec_path, os.X_OK):
                 if not found_filter:
index a238e7358d2bd50d7e8be1982d2466dd03a93343..42ab473f7f1191f901e5b091c87aa5014fa76b76 100644 (file)
 import os
 import subprocess
 
+import unittest2 as unittest
+
 from quantum.rootwrap import filters
 from quantum.rootwrap import wrapper
-import unittest
 
 
 class RootwrapTestCase(unittest.TestCase):
@@ -108,6 +109,47 @@ class RootwrapTestCase(unittest.TestCase):
         self.assertEqual(f.get_command(usercmd), ['/bin/cat', goodfn])
         self.assertTrue(f.match(usercmd))
 
+    def test_IpFilter_non_netns(self):
+        f = filters.IpFilter('/sbin/ip', 'root')
+        self.assertTrue(f.match(['ip', 'link', 'list']))
+
+    def _test_IpFilter_netns_helper(self, action):
+        f = filters.IpFilter('/sbin/ip', 'root')
+        self.assertTrue(f.match(['ip', 'link', action]))
+
+    def test_IpFilter_netns_add(self):
+        self._test_IpFilter_netns_helper('add')
+
+    def test_IpFilter_netns_delete(self):
+        self._test_IpFilter_netns_helper('delete')
+
+    def test_IpFilter_netns_list(self):
+        self._test_IpFilter_netns_helper('list')
+
+    def test_IpNetnsExecFilter_match(self):
+        f = filters.IpNetnsExecFilter('/sbin/ip', 'root')
+        self.assertTrue(
+            f.match(['ip', 'netns', 'exec', 'foo', 'ip', 'link', 'list']))
+
+    def test_IpNetnsExecFilter_nomatch(self):
+        f = filters.IpNetnsExecFilter('/sbin/ip', 'root')
+        self.assertFalse(f.match(['ip', 'link', 'list']))
+
+    def test_match_filter_recurses_exec_command_filter(self):
+        filter_list = [filters.IpNetnsExecFilter('/sbin/ip', 'root'),
+                       filters.IpFilter('/sbin/ip', 'root')]
+        args = ['ip', 'netns', 'exec', 'foo', 'ip', 'link', 'list']
+
+        self.assertIsNotNone(wrapper.match_filter(filter_list, args))
+
+    def test_match_filter_recurses_exec_command_filter(self):
+        filter_list = [filters.IpNetnsExecFilter('/sbin/ip', 'root'),
+                       filters.IpFilter('/sbin/ip', 'root')]
+        args = ['ip', 'netns', 'exec', 'foo', 'ip', 'netns', 'exec', 'bar',
+                'ip', 'link', 'list']
+
+        self.assertIsNone(wrapper.match_filter(filter_list, args))
+
     def test_skips(self):
         # Check that all filters are skipped and that the last matches
         usercmd = ["cat", "/"]