]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
pybind: ceph_argparse: validate incorrectly formed targets 3285/head
authorJoao Eduardo Luis <joao@redhat.com>
Fri, 2 Jan 2015 17:39:36 +0000 (17:39 +0000)
committerJoao Eduardo Luis <joao@redhat.com>
Fri, 16 Jan 2015 16:41:40 +0000 (16:41 +0000)
Prior to this patch find_cmd_target() would perform the following
parsing for any given command:

- check if it's a "tell" to a parseable CephName
  (i.e., ceph tell <type.id> ...)
  - if so, return <type>, <id>

- check if it's a "tell" to a parseable PG id
  (e.g., ceph tell 0.4a)
  - if so, return 'pg', <pgid>

- check if it's a "pg" command to a parseable PG id
  (e.g., ceph pg 0.4a)
  - if so, return 'pg', <pgid>

- otherwise return 'mon', ''

However, parsing of CephName and CephPgid is performed in a relaxed
fashion, and tightening those checks requirements end up having
nefarious effects on properly formed commands, whereas keeping them
relaxed ends up having us returning 'mon','' in the end for a clearly
malformed target (e.g., 'ceph tell foo ...').

This patch fixes this behavior by adding a new check:

- if command is a "tell" and we were not able to parse either a CephName
  nor a PG id, then explicitely validate the target as a CephName (given
  we would be sending to a monitor anyway, we can just as well validate
  a 'tell' as a CephName).
  - if validation fails, we will propagate exceptions referring to the
    cause of the validation failure.

Fixes: #10439
Signed-off-by: Joao Eduardo Luis <joao@redhat.com>
src/ceph.in
src/pybind/ceph_argparse.py

index 9a7092b972c0095b30dc5956b9ccb20a9ae3a6cf..53f808733373f85d99e9caeab1556185d0442634 100755 (executable)
@@ -425,7 +425,12 @@ def new_style_command(parsed_args, cmdargs, target, sigdict, inbuf, verbose):
                 if interactive_input in ['q', 'quit', 'Q']:
                     return 0, '', ''
                 cmdargs = parse_cmdargs(interactive_input.split())[2]
-                target = find_cmd_target(cmdargs)
+                try:
+                    target = find_cmd_target(cmdargs)
+                except Exception as e:
+                    print >> sys.stderr, \
+                            'error handling command target: {0}'.format(e)
+                    return 1
                 valid_dict = validate_command(sigdict, cmdargs, verbose)
                 if valid_dict:
                     if parsed_args.output_format:
@@ -753,7 +758,12 @@ def main():
     if parsed_args.status:
         childargs.insert(0, 'status')
 
-    target = find_cmd_target(childargs)
+    try:
+        target = find_cmd_target(childargs)
+    except Exception as e:
+        print >> sys.stderr, \
+                'error handling command target: {0}'.format(e)
+        return 1
 
     # Repulsive hack to handle tell: lop off 'tell' and target
     # and validate the rest of the command.  'target' is already
index 85867fb32c765f7acc09bf660cf1dfb819e7e2e5..029a552be148e5174c46cff73c30a967cf12e909 100644 (file)
@@ -1005,6 +1005,30 @@ def find_cmd_target(childargs):
             # pg doesn't need revalidation; the string is fine
             return 'pg', valid_dict['pgid']
 
+    # If we reached this far it must mean that so far we've been unable to
+    # obtain a proper target from childargs.  This may mean that we are not
+    # dealing with a 'tell' command, or that the specified target is invalid.
+    # If the latter, we likely were unable to catch it because we were not
+    # really looking for it: first we tried to parse a 'CephName' (osd, mon,
+    # mds, followed by and id); given our failure to parse, we tried to parse
+    # a 'CephPgid' instead (e.g., 0.4a).  Considering we got this far though
+    # we were unable to do so.
+    #
+    # We will now check if this is a tell and, if so, forcefully validate the
+    # target as a 'CephName'.  This must be so because otherwise we will end
+    # up sending garbage to a monitor, which is the default target when a
+    # target is not explicitly specified.
+    # e.g.,
+    #   'ceph status' -> target is any one monitor
+    #   'ceph tell mon.* status -> target is all monitors
+    #   'ceph tell foo status -> target is invalid!
+    if len(childargs) > 1 and childargs[0] == 'tell':
+        name = CephName()
+        # CephName.valid() raises on validation error; find_cmd_target()'s
+        # caller should handle them
+        name.valid(childargs[1])
+        return name.nametype, name.nameid
+
     sig = parse_funcsig(['pg', {'name':'pgid', 'type':'CephPgid'}])
     try:
         valid_dict = validate(childargs, sig, partial=True)