From e20a507113ff1126aeb4a97b806390ea377fe292 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 31 Jul 2018 22:26:52 -0400 Subject: New upstream version 1.10.2 --- tools/hook-scripts/CVE-2017-9800-pre-commit.py | 74 ++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100755 tools/hook-scripts/CVE-2017-9800-pre-commit.py (limited to 'tools/hook-scripts/CVE-2017-9800-pre-commit.py') diff --git a/tools/hook-scripts/CVE-2017-9800-pre-commit.py b/tools/hook-scripts/CVE-2017-9800-pre-commit.py new file mode 100755 index 0000000..2971545 --- /dev/null +++ b/tools/hook-scripts/CVE-2017-9800-pre-commit.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python2 + +# Licensed under the same terms as Subversion: the Apache License, Version 2.0 +# +# pre-commit hook script for Subversion CVE-2017-9800 +# +# This prevents commits that set svn:externals containing suspicions +# svn+ssh:// URLs. +# +# With this script installed a commit like the one below should fail: +# +# svnmucc -mm propset svn:externals 'svn+ssh://-localhost/X X' REPOSITORY-URL + +import sys, locale, urllib, urlparse, curses.ascii +from svn import wc, repos, fs + +# A simple whitelist to ensure these are not suspicious: +# user@server +# [::1]:22 +# server-name +# server_name +# 127.0.0.1 +# with an extra restriction that a leading '-' is suspicious. +def suspicious_host(host): + if host[0] == '-': + return True + for char in host: + if not curses.ascii.isalnum(char) and not char in ':.-_[]@': + return True + return False + +native = locale.getlocale()[1] +if not native: native = 'ascii' +repos_handle = repos.open(sys.argv[1].decode(native).encode('utf-8')) +fs_handle = repos.fs(repos_handle) +txn_handle = fs.open_txn(fs_handle, sys.argv[2].decode(native).encode('utf-8')) +txn_root = fs.txn_root(txn_handle) +rev_root = fs.revision_root(fs_handle, fs.txn_root_base_revision(txn_root)) + +for path, change in fs.paths_changed2(txn_root).iteritems(): + + if change.prop_mod: + + # The new value, if any + txn_prop = fs.node_prop(txn_root, path, "svn:externals") + if not txn_prop: + continue + + # The old value, if any + rev_prop = None + if change.change_kind == fs.path_change_modify: + rev_prop = fs.node_prop(rev_root, path, "svn:externals") + elif change.change_kind == fs.path_change_add and change.copyfrom_path: + copy_root = fs.revision_root(fs_handle, change.copyfrom_rev) + rev_prop = fs.node_prop(copy_root, change.copyfrom_path, + "svn:externals") + + if txn_prop != rev_prop: + error_path = path.decode('utf-8').encode(native, 'replace') + externals = [] + try: + externals = wc.parse_externals_description2(path, txn_prop) + except: + sys.stderr.write("Commit blocked due to parse failure " + "on svn:externals for %s\n" % error_path) + sys.exit(1) + for external in externals: + parsed = urlparse.urlparse(urllib.unquote(external.url)) + if (parsed and parsed.scheme[:4] == "svn+" + and suspicious_host(parsed.netloc)): + sys.stderr.write("Commit blocked due to suspicious URL " + "containing %r in svn:externals " + "for %s\n" % (parsed.netloc, error_path)) + sys.exit(1) -- cgit v1.2.3