]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Allow spaces in quoted SSH command arguments
authorLuis A. Garcia <luis@linux.vnet.ibm.com>
Tue, 29 Oct 2013 18:44:12 +0000 (18:44 +0000)
committerLuis A. Garcia <luis@linux.vnet.ibm.com>
Tue, 29 Oct 2013 22:03:19 +0000 (22:03 +0000)
The check_ssh_injection() method was rejecting arguments with spaces
even when they were quoted, this was causing problems with some volume
driver commands such as commands for a storage pool with spaces in the
name.

Closes-Bug: #1244415
Change-Id: Ie4b809e1b39fdb752cf634e6d3c0a3924d8ac52b

cinder/tests/test_utils.py
cinder/utils.py

index fe1f542141f43716994bad304e9bd88715bf1152..cef8d8553ab2ca7ae2935d8bd0ddcec1865bff29 100644 (file)
@@ -456,16 +456,48 @@ class GenericUtilsTestCase(test.TestCase):
     def test_check_ssh_injection(self):
         cmd_list = ['ssh', '-D', 'my_name@name_of_remote_computer']
         self.assertIsNone(utils.check_ssh_injection(cmd_list))
+        cmd_list = ['echo', '"quoted arg with space"']
+        self.assertIsNone(utils.check_ssh_injection(cmd_list))
+        cmd_list = ['echo', "'quoted arg with space'"]
+        self.assertIsNone(utils.check_ssh_injection(cmd_list))
 
     def test_check_ssh_injection_on_error(self):
-        with_space = ['shh', 'my_name@      name_of_remote_computer']
-        with_danger_char = ['||', 'my_name@name_of_remote_computer']
+        with_unquoted_space = ['shh', 'my_name@      name_of_remote_computer']
         self.assertRaises(exception.SSHInjectionThreat,
                           utils.check_ssh_injection,
-                          with_space)
+                          with_unquoted_space)
+        with_danger_char = ['||', 'my_name@name_of_remote_computer']
         self.assertRaises(exception.SSHInjectionThreat,
                           utils.check_ssh_injection,
                           with_danger_char)
+        with_special = ['cmd', 'virus;ls']
+        self.assertRaises(exception.SSHInjectionThreat,
+                          utils.check_ssh_injection,
+                          with_special)
+        quoted_with_unescaped = ['cmd', '"arg\"withunescaped"']
+        self.assertRaises(exception.SSHInjectionThreat,
+                          utils.check_ssh_injection,
+                          quoted_with_unescaped)
+        bad_before_quotes = ['cmd', 'virus;"quoted argument"']
+        self.assertRaises(exception.SSHInjectionThreat,
+                          utils.check_ssh_injection,
+                          bad_before_quotes)
+        bad_after_quotes = ['echo', '"quoted argument";rm -rf']
+        self.assertRaises(exception.SSHInjectionThreat,
+                          utils.check_ssh_injection,
+                          bad_after_quotes)
+        bad_within_quotes = ['echo', "'quoted argument `rm -rf`'"]
+        self.assertRaises(exception.SSHInjectionThreat,
+                          utils.check_ssh_injection,
+                          bad_within_quotes)
+        with_multiple_quotes = ['echo', '"quoted";virus;"quoted"']
+        self.assertRaises(exception.SSHInjectionThreat,
+                          utils.check_ssh_injection,
+                          with_multiple_quotes)
+        with_multiple_quotes = ['echo', '"quoted";virus;\'quoted\'']
+        self.assertRaises(exception.SSHInjectionThreat,
+                          utils.check_ssh_injection,
+                          with_multiple_quotes)
 
     def test_create_channel(self):
         client = paramiko.SSHClient()
index a92180b9d02e4afe490a60ef5fce384a4b1a7508..de3d2481defad02cfde10919766a652602ed4a24 100644 (file)
@@ -149,10 +149,21 @@ def check_ssh_injection(cmd_list):
     # Check whether injection attacks exist
     for arg in cmd_list:
         arg = arg.strip()
-        # First, check no space in the middle of arg
-        arg_len = len(arg.split())
-        if arg_len > 1:
-            raise exception.SSHInjectionThreat(command=str(cmd_list))
+
+        # Check for matching quotes on the ends
+        is_quoted = re.match('^(?P<quote>[\'"])(?P<quoted>.*)(?P=quote)$', arg)
+        if is_quoted:
+            # Check for unescaped quotes within the quoted argument
+            quoted = is_quoted.group('quoted')
+            if quoted:
+                if (re.match('[\'"]', quoted) or
+                        re.search('[^\\\\][\'"]', quoted)):
+                    raise exception.SSHInjectionThreat(command=str(cmd_list))
+        else:
+            # We only allow spaces within quoted arguments, and that
+            # is the only special character allowed within quotes
+            if len(arg.split()) > 1:
+                raise exception.SSHInjectionThreat(command=str(cmd_list))
 
         # Second, check whether danger character in command. So the shell
         # special operator must be a single argument.