From c4548f68ca9565febe167d6ae2f2c96f550051e7 Mon Sep 17 00:00:00 2001 From: Joao Eduardo Luis Date: Fri, 2 Jan 2015 17:39:36 +0000 Subject: [PATCH] pybind: ceph_argparse: validate incorrectly formed targets 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 ...) - if so, return , - check if it's a "tell" to a parseable PG id (e.g., ceph tell 0.4a) - if so, return 'pg', - check if it's a "pg" command to a parseable PG id (e.g., ceph pg 0.4a) - if so, return 'pg', - 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 --- src/ceph.in | 14 ++++++++++++-- src/pybind/ceph_argparse.py | 24 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/ceph.in b/src/ceph.in index 9a7092b972c..53f80873337 100755 --- a/src/ceph.in +++ b/src/ceph.in @@ -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 diff --git a/src/pybind/ceph_argparse.py b/src/pybind/ceph_argparse.py index 85867fb32c7..029a552be14 100644 --- a/src/pybind/ceph_argparse.py +++ b/src/pybind/ceph_argparse.py @@ -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) -- 2.47.3