From 614d4e40e148520ac511cbe0606bcbdcf24c8a08 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Sat, 21 Nov 2009 15:18:02 -0500 Subject: [PATCH] Added restrict_file_access to becommands' execute() args. + associated adjustments in other files. See cmdutil.restrict_file_access.__doc__ for an explanation of the security hole this closes. --- README.dev | 10 +++++++++- becommands/assign.py | 2 +- becommands/close.py | 2 +- becommands/comment.py | 2 +- becommands/commit.py | 4 +++- becommands/depend.py | 2 +- becommands/diff.py | 2 +- becommands/email_bugs.py | 2 +- becommands/help.py | 2 +- becommands/html.py | 2 +- becommands/import_xml.py | 4 +++- becommands/init.py | 2 +- becommands/list.py | 2 +- becommands/merge.py | 2 +- becommands/new.py | 2 +- becommands/open.py | 2 +- becommands/remove.py | 2 +- becommands/set.py | 2 +- becommands/severity.py | 2 +- becommands/show.py | 2 +- becommands/status.py | 2 +- becommands/subscribe.py | 2 +- becommands/tag.py | 2 +- becommands/target.py | 2 +- interfaces/email/interactive/be-handle-mail | 3 ++- libbe/cmdutil.py | 21 +++++++++++++++++++-- 26 files changed, 57 insertions(+), 27 deletions(-) diff --git a/README.dev b/README.dev index ddc3a88..fb4f471 100644 --- a/README.dev +++ b/README.dev @@ -10,11 +10,19 @@ To fit into the current framework, your extension module should provide the following elements: __desc__ A short string describing the purpose of your plugin - execute(args) + execute(args, manipulate_encodings=True, restrict_file_access=False) The entry function for your plugin. args is everything from sys.argv after the name of your plugin (e.g. for the command `be open abc', args=['abc']). + manipulate_encodings should be passed through to any calls to + bugdir.BugDir(). See the BugDir documentation for details. + + If restrict_file_access==True, you should call + cmdutil.restrict_file_access(bugdir, path) + before attempting to read or write a file. See the + restrict_file_access documentation for details. + Note: be supports command-completion. To avoid raising errors you need to deal with possible '--complete' options and arguments. See the 'Command completion' section below for more information. diff --git a/becommands/assign.py b/becommands/assign.py index 31aa607..2c78f69 100644 --- a/becommands/assign.py +++ b/becommands/assign.py @@ -21,7 +21,7 @@ from libbe import cmdutil, bugdir __desc__ = __doc__ -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> import os >>> bd = bugdir.SimpleBugDir() diff --git a/becommands/close.py b/becommands/close.py index d65c4e0..a14cea8 100644 --- a/becommands/close.py +++ b/becommands/close.py @@ -21,7 +21,7 @@ from libbe import cmdutil, bugdir __desc__ = __doc__ -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> from libbe import bugdir >>> import os diff --git a/becommands/comment.py b/becommands/comment.py index a600e9f..8e899ce 100644 --- a/becommands/comment.py +++ b/becommands/comment.py @@ -21,7 +21,7 @@ import os import sys __desc__ = __doc__ -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> import time >>> bd = bugdir.SimpleBugDir() diff --git a/becommands/commit.py b/becommands/commit.py index b530fdc..39d1e2e 100644 --- a/becommands/commit.py +++ b/becommands/commit.py @@ -18,7 +18,7 @@ from libbe import cmdutil, bugdir, editor, vcs import sys __desc__ = __doc__ -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> import os >>> from libbe import bug @@ -49,6 +49,8 @@ def execute(args, manipulate_encodings=True): elif options.body == "EDITOR": body = editor.editor_string("Please enter your commit message above") else: + if restrict_file_access == True: + cmdutil.restrict_file_access(bd, options.body) body = bd.vcs.get_file_contents(options.body, allow_no_vcs=True) try: revision = bd.vcs.commit(summary, body=body, diff --git a/becommands/depend.py b/becommands/depend.py index 044aaff..f50d693 100644 --- a/becommands/depend.py +++ b/becommands/depend.py @@ -35,7 +35,7 @@ class BrokenLink (Exception): self.blocking_bug = blocking_bug -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> from libbe import utility >>> bd = bugdir.SimpleBugDir() diff --git a/becommands/diff.py b/becommands/diff.py index e71da9b..6477934 100644 --- a/becommands/diff.py +++ b/becommands/diff.py @@ -21,7 +21,7 @@ from libbe import cmdutil, bugdir, diff import os __desc__ = __doc__ -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> import os >>> bd = bugdir.SimpleBugDir() diff --git a/becommands/email_bugs.py b/becommands/email_bugs.py index 27f0b91..d0366df 100644 --- a/becommands/email_bugs.py +++ b/becommands/email_bugs.py @@ -33,7 +33,7 @@ __desc__ = __doc__ sendmail='/usr/sbin/sendmail -t' -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> import os >>> from libbe import bug diff --git a/becommands/help.py b/becommands/help.py index c12c56a..99ab8c4 100644 --- a/becommands/help.py +++ b/becommands/help.py @@ -20,7 +20,7 @@ from libbe import cmdutil, utility __desc__ = __doc__ -def execute(args, manipulate_encodings=False): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ Print help of specified command (the manipulate_encodings argument is ignored). diff --git a/becommands/html.py b/becommands/html.py index b0640da..622a531 100644 --- a/becommands/html.py +++ b/becommands/html.py @@ -21,7 +21,7 @@ import xml.sax.saxutils, htmlentitydefs __desc__ = __doc__ -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> import os >>> bd = bugdir.SimpleBugDir() diff --git a/becommands/import_xml.py b/becommands/import_xml.py index 928ca46..a74d329 100644 --- a/becommands/import_xml.py +++ b/becommands/import_xml.py @@ -24,7 +24,7 @@ except ImportError: # look for non-core module from elementtree import ElementTree __desc__ = __doc__ -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> import time >>> import StringIO @@ -69,6 +69,8 @@ def execute(args, manipulate_encodings=True): if filename == '-': xml = sys.stdin.read() else: + if restrict_file_access == True: + cmdutil.restrict_file_access(bd, options.body) xml = bd.vcs.get_file_contents(filename, allow_no_vcs=True) str_xml = xml.encode('unicode_escape').replace(r'\n', '\n') # unicode read + encode to string so we know the encoding, diff --git a/becommands/init.py b/becommands/init.py index 39fb006..7d6d475 100644 --- a/becommands/init.py +++ b/becommands/init.py @@ -20,7 +20,7 @@ import os.path from libbe import cmdutil, bugdir __desc__ = __doc__ -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> from libbe import utility, vcs >>> import os diff --git a/becommands/list.py b/becommands/list.py index 14e387b..4711789 100644 --- a/becommands/list.py +++ b/becommands/list.py @@ -26,7 +26,7 @@ __desc__ = __doc__ AVAILABLE_CMPS = [fn[4:] for fn in dir(bug) if fn[:4] == 'cmp_'] AVAILABLE_CMPS.remove("attr") # a cmp_* template. -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> import os >>> bd = bugdir.SimpleBugDir() diff --git a/becommands/merge.py b/becommands/merge.py index 766af56..31c781f 100644 --- a/becommands/merge.py +++ b/becommands/merge.py @@ -19,7 +19,7 @@ from libbe import cmdutil, bugdir import os, copy __desc__ = __doc__ -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> from libbe import utility >>> bd = bugdir.SimpleBugDir() diff --git a/becommands/new.py b/becommands/new.py index 30a7d28..92d61e4 100644 --- a/becommands/new.py +++ b/becommands/new.py @@ -20,7 +20,7 @@ from libbe import cmdutil, bugdir import sys __desc__ = __doc__ -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> import os, time >>> from libbe import bug diff --git a/becommands/open.py b/becommands/open.py index 1b4c23e..c2c15e2 100644 --- a/becommands/open.py +++ b/becommands/open.py @@ -21,7 +21,7 @@ from libbe import cmdutil, bugdir __desc__ = __doc__ -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> import os >>> bd = bugdir.SimpleBugDir() diff --git a/becommands/remove.py b/becommands/remove.py index d265e5c..e4f0065 100644 --- a/becommands/remove.py +++ b/becommands/remove.py @@ -18,7 +18,7 @@ from libbe import cmdutil, bugdir __desc__ = __doc__ -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> from libbe import mapfile >>> import os diff --git a/becommands/set.py b/becommands/set.py index e5cab8d..c8c5a2c 100644 --- a/becommands/set.py +++ b/becommands/set.py @@ -32,7 +32,7 @@ def _value_string(bd, setting): val = None return str(val) -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> import os >>> bd = bugdir.SimpleBugDir() diff --git a/becommands/severity.py b/becommands/severity.py index f42f740..524976b 100644 --- a/becommands/severity.py +++ b/becommands/severity.py @@ -21,7 +21,7 @@ from libbe import cmdutil, bugdir, bug __desc__ = __doc__ -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> import os >>> bd = bugdir.SimpleBugDir() diff --git a/becommands/show.py b/becommands/show.py index 11890a8..557c63a 100644 --- a/becommands/show.py +++ b/becommands/show.py @@ -22,7 +22,7 @@ import sys from libbe import cmdutil, bugdir, comment, version, _version __desc__ = __doc__ -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> import os >>> bd = bugdir.SimpleBugDir() diff --git a/becommands/status.py b/becommands/status.py index bf66c26..fd31c97 100644 --- a/becommands/status.py +++ b/becommands/status.py @@ -18,7 +18,7 @@ from libbe import cmdutil, bugdir, bug __desc__ = __doc__ -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> import os >>> bd = bugdir.SimpleBugDir() diff --git a/becommands/subscribe.py b/becommands/subscribe.py index 0a23057..051341b 100644 --- a/becommands/subscribe.py +++ b/becommands/subscribe.py @@ -55,7 +55,7 @@ class InvalidType (ValueError): self.type_root = type_root -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> bd = bugdir.SimpleBugDir() >>> bd.set_sync_with_disk(True) diff --git a/becommands/tag.py b/becommands/tag.py index e6debb4..e22cb70 100644 --- a/becommands/tag.py +++ b/becommands/tag.py @@ -19,7 +19,7 @@ from libbe import cmdutil, bugdir import os, copy __desc__ = __doc__ -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> from libbe import utility >>> bd = bugdir.SimpleBugDir() diff --git a/becommands/target.py b/becommands/target.py index 672eb06..efb2479 100644 --- a/becommands/target.py +++ b/becommands/target.py @@ -22,7 +22,7 @@ from libbe import cmdutil, bugdir __desc__ = __doc__ -def execute(args, manipulate_encodings=True): +def execute(args, manipulate_encodings=True, restrict_file_access=False): """ >>> import os >>> bd = bugdir.SimpleBugDir() diff --git a/interfaces/email/interactive/be-handle-mail b/interfaces/email/interactive/be-handle-mail index bd37f55..e0e3490 100755 --- a/interfaces/email/interactive/be-handle-mail +++ b/interfaces/email/interactive/be-handle-mail @@ -242,7 +242,8 @@ class Command (object): os.chdir(BE_DIR) try: self.ret = libbe.cmdutil.execute(self.command, self.args, - manipulate_encodings=False) + manipulate_encodings=False, + restrict_file_access=True) except libbe.cmdutil.GetHelp: print libbe.cmdutil.help(command) except libbe.cmdutil.GetCompletions: diff --git a/libbe/cmdutil.py b/libbe/cmdutil.py index 96430eb..e37750d 100644 --- a/libbe/cmdutil.py +++ b/libbe/cmdutil.py @@ -76,11 +76,12 @@ def get_command(command_name): return cmd -def execute(cmd, args, manipulate_encodings=True): +def execute(cmd, args, manipulate_encodings=True, restrict_file_access=False): enc = encoding.get_encoding() cmd = get_command(cmd) ret = cmd.execute([a.decode(enc) for a in args], - manipulate_encodings=manipulate_encodings) + manipulate_encodings=manipulate_encodings, + restrict_file_access=restrict_file_access) if ret == None: ret = 0 return ret @@ -213,6 +214,22 @@ def underlined(instring): return "%s\n%s" % (instring, "="*len(instring)) +def restrict_file_access(bugdir, path): + """ + Check that the file at path is inside bugdir.root. This is + important if you allow other users to execute becommands with your + username (e.g. if you're running be-handle-mail through your + ~/.procmailrc). If this check wasn't made, a user could e.g. + run + be commit -b ~/.ssh/id_rsa "Hack to expose ssh key" + which would expose your ssh key to anyone who could read the VCS + log. + """ + in_root = bugdir.vcs.path_in_root(path, bugdir.root) + if in_root == False: + raise UserError('file access restricted!\n %s not in %s' + % (path, bugdir.root)) + def parse_id(id): """ Return (bug_id, comment_id) tuple. -- 2.26.2