diff --git a/CVE-2014-3539-disable-doa.patch b/CVE-2014-3539-disable-doa.patch new file mode 100644 index 0000000..d1248c0 --- /dev/null +++ b/CVE-2014-3539-disable-doa.patch @@ -0,0 +1,251 @@ +From 5cd16e47baf76f57b0dab0d9ab1684a8e02ea6a8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Mat=C4=9Bj=20Cepl?= +Date: Wed, 11 Feb 2015 22:06:44 +0100 +Subject: [PATCH 1/2] Simple hackish solution to CVE-2014-3539. + +This doesn't resolve the issue, but at least people using DOA should be +intentional about it and aware of the security risks. + +It is also necessary explicitly switch on 'perform_doa' preference for +tests that require it. + +Fixes #105 +--- + rope/base/default_config.py | 12 +++++++++++- + ropetest/advanced_oi_test.py | 23 +++++++++++++++++++++++ + 2 files changed, 34 insertions(+), 1 deletion(-) + +diff --git a/rope/base/default_config.py b/rope/base/default_config.py +index 0ee9937..e46509f 100644 +--- a/rope/base/default_config.py ++++ b/rope/base/default_config.py +@@ -46,7 +46,17 @@ def set_prefs(prefs): + + # If `False` when running modules or unit tests "dynamic object + # analysis" is turned off. This makes them much faster. +- prefs['perform_doa'] = True ++ # ++ # There is also a security risk involved with this (CVE-2014-3539), ++ # because during by this rope can be persuaded to open under some ++ # circumstances a network port for short moment of time, which can ++ # be used to push commands to the running process, so that such ++ # process could proceed some commands under the privilegis of the ++ # user running rope. Therefore this variable defaults to False, and ++ # anybody who would like to change its value to True is advised to ++ # make sure the computer is well firewalled against possible ++ # intruders. ++ prefs['perform_doa'] = False + + # Rope can check the validity of its object DB when running. + prefs['validate_objectdb'] = True +diff --git a/ropetest/advanced_oi_test.py b/ropetest/advanced_oi_test.py +index 4130fae..e862307 100644 +--- a/ropetest/advanced_oi_test.py ++++ b/ropetest/advanced_oi_test.py +@@ -17,6 +17,7 @@ def tearDown(self): + super(DynamicOITest, self).tearDown() + + def test_simple_dti(self): ++ self.project.prefs['perform_doa'] = True + mod = testutils.create_module(self.project, 'mod') + code = 'def a_func(arg):\n return eval("arg")\n' \ + 'a_var = a_func(a_func)\n' +@@ -27,6 +28,7 @@ def test_simple_dti(self): + pymod['a_var'].get_object()) + + def test_module_dti(self): ++ self.project.prefs['perform_doa'] = True + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + code = 'import mod1\ndef a_func(arg):\n return eval("arg")\n' \ +@@ -38,6 +40,7 @@ def test_module_dti(self): + pymod2['a_var'].get_object()) + + def test_class_from_another_module_dti(self): ++ self.project.prefs['perform_doa'] = True + mod1 = testutils.create_module(self.project, 'mod1') + mod2 = testutils.create_module(self.project, 'mod2') + code1 = 'class AClass(object):\n pass\n' +@@ -54,6 +57,7 @@ def test_class_from_another_module_dti(self): + + def test_class_dti(self): + mod = testutils.create_module(self.project, 'mod') ++ self.project.prefs['perform_doa'] = True + code = 'class AClass(object):\n pass\n' \ + '\ndef a_func(arg):\n return eval("arg")\n' \ + 'a_var = a_func(AClass)\n' +@@ -64,6 +68,7 @@ def test_class_dti(self): + pymod['a_var'].get_object()) + + def test_instance_dti(self): ++ self.project.prefs['perform_doa'] = True + mod = testutils.create_module(self.project, 'mod') + code = 'class AClass(object):\n pass\n' \ + '\ndef a_func(arg):\n return eval("arg()")\n' \ +@@ -75,6 +80,7 @@ def test_instance_dti(self): + pymod['a_var'].get_object().get_type()) + + def test_method_dti(self): ++ self.project.prefs['perform_doa'] = True + mod = testutils.create_module(self.project, 'mod') + code = 'class AClass(object):\n def a_method(self, arg):\n' \ + ' return eval("arg()")\n' \ +@@ -87,6 +93,7 @@ def test_method_dti(self): + pymod['a_var'].get_object().get_type()) + + def test_function_argument_dti(self): ++ self.project.prefs['perform_doa'] = True + mod = testutils.create_module(self.project, 'mod') + code = 'def a_func(arg):\n pass\n' \ + 'a_func(a_func)\n' +@@ -97,6 +104,7 @@ def test_function_argument_dti(self): + pyscope.get_scopes()[0]['arg'].get_object()) + + def test_classes_with_the_same_name(self): ++ self.project.prefs['perform_doa'] = True + mod = testutils.create_module(self.project, 'mod') + code = 'def a_func(arg):\n class AClass(object):\n' \ + ' pass\n return eval("arg")\n' \ +@@ -109,6 +117,7 @@ def test_classes_with_the_same_name(self): + pymod['a_var'].get_object()) + + def test_nested_classes(self): ++ self.project.prefs['perform_doa'] = True + mod = testutils.create_module(self.project, 'mod') + code = 'def a_func():\n class AClass(object):\n' \ + ' pass\n return AClass\n' \ +@@ -121,6 +130,7 @@ def test_nested_classes(self): + pyscope['a_var'].get_object()) + + def test_function_argument_dti2(self): ++ self.project.prefs['perform_doa'] = True + mod = testutils.create_module(self.project, 'mod') + code = 'def a_func(arg, a_builtin_type):\n pass\n' \ + 'a_func(a_func, [])\n' +@@ -131,6 +141,7 @@ def test_function_argument_dti2(self): + pyscope.get_scopes()[0]['arg'].get_object()) + + def test_dti_and_concluded_data_invalidation(self): ++ self.project.prefs['perform_doa'] = True + mod = testutils.create_module(self.project, 'mod') + code = 'def a_func(arg):\n return eval("arg")\n' \ + 'a_var = a_func(a_func)\n' +@@ -142,6 +153,7 @@ def test_dti_and_concluded_data_invalidation(self): + pymod['a_var'].get_object()) + + def test_list_objects_and_dynamicoi(self): ++ self.project.prefs['perform_doa'] = True + mod = testutils.create_module(self.project, 'mod') + code = 'class C(object):\n pass\n' \ + 'def a_func(arg):\n return eval("arg")\n' \ +@@ -154,6 +166,7 @@ def test_list_objects_and_dynamicoi(self): + self.assertEquals(c_class, a_var.get_type()) + + def test_for_loops_and_dynamicoi(self): ++ self.project.prefs['perform_doa'] = True + mod = testutils.create_module(self.project, 'mod') + code = 'class C(object):\n pass\n' \ + 'def a_func(arg):\n return eval("arg")\n' \ +@@ -166,6 +179,7 @@ def test_for_loops_and_dynamicoi(self): + self.assertEquals(c_class, a_var.get_type()) + + def test_dict_objects_and_dynamicoi(self): ++ self.project.prefs['perform_doa'] = True + mod = testutils.create_module(self.project, 'mod') + code = 'class C(object):\n pass\n' \ + 'def a_func(arg):\n return eval("arg")\n' \ +@@ -178,6 +192,7 @@ def test_dict_objects_and_dynamicoi(self): + self.assertEquals(c_class, a_var.get_type()) + + def test_dict_keys_and_dynamicoi(self): ++ self.project.prefs['perform_doa'] = True + mod = testutils.create_module(self.project, 'mod') + code = 'class C(object):\n pass\n' \ + 'def a_func(arg):\n return eval("arg")\n' \ +@@ -190,6 +205,7 @@ def test_dict_keys_and_dynamicoi(self): + self.assertEquals(c_class, a_var.get_type()) + + def test_dict_keys_and_dynamicoi2(self): ++ self.project.prefs['perform_doa'] = True + mod = testutils.create_module(self.project, 'mod') + code = 'class C1(object):\n pass\nclass C2(object):\n pass\n' \ + 'def a_func(arg):\n return eval("arg")\n' \ +@@ -205,6 +221,7 @@ def test_dict_keys_and_dynamicoi2(self): + self.assertEquals(c2_class, b_var.get_type()) + + def test_strs_and_dynamicoi(self): ++ self.project.prefs['perform_doa'] = True + mod = testutils.create_module(self.project, 'mod') + code = 'def a_func(arg):\n return eval("arg")\n' \ + 'a_var = a_func("hey")\n' +@@ -239,6 +256,7 @@ def complex_to_textual(pyobject): + + def test_arguments_with_keywords(self): + mod = testutils.create_module(self.project, 'mod') ++ self.project.prefs['perform_doa'] = True + code = 'class C1(object):\n pass\nclass C2(object):\n pass\n' \ + 'def a_func(arg):\n return eval("arg")\n' \ + 'a = a_func(arg=C1())\nb = a_func(arg=C2())\n' +@@ -254,6 +272,7 @@ def test_arguments_with_keywords(self): + + def test_a_function_with_different_returns(self): + mod = testutils.create_module(self.project, 'mod') ++ self.project.prefs['perform_doa'] = True + code = 'class C1(object):\n pass\nclass C2(object):\n pass\n' \ + 'def a_func(arg):\n return eval("arg")\n' \ + 'a = a_func(C1())\nb = a_func(C2())\n' +@@ -269,6 +288,7 @@ def test_a_function_with_different_returns(self): + + def test_a_function_with_different_returns2(self): + mod = testutils.create_module(self.project, 'mod') ++ self.project.prefs['perform_doa'] = True + code = 'class C1(object):\n pass\nclass C2(object):\n pass\n' \ + 'def a_func(p):\n if p == C1:\n return C1()\n' \ + ' else:\n return C2()\n' \ +@@ -284,6 +304,7 @@ def test_a_function_with_different_returns2(self): + self.assertEquals(c2_class, b_var.get_type()) + + def test_ignoring_star_args(self): ++ self.project.prefs['perform_doa'] = True + mod = testutils.create_module(self.project, 'mod') + code = 'class C1(object):\n pass\nclass C2(object):\n pass\n' \ + 'def a_func(p, *args):' \ +@@ -301,6 +322,7 @@ def test_ignoring_star_args(self): + self.assertEquals(c2_class, b_var.get_type()) + + def test_ignoring_double_star_args(self): ++ self.project.prefs['perform_doa'] = True + mod = testutils.create_module(self.project, 'mod') + code = 'class C1(object):\n pass\nclass C2(object):\n pass\n' \ + 'def a_func(p, *kwds, **args):\n ' \ +@@ -330,6 +352,7 @@ def test_invalidating_data_after_changing(self): + pymod['a_var'].get_object()) + + def test_invalidating_data_after_moving(self): ++ self.project.prefs['perform_doa'] = True + mod2 = testutils.create_module(self.project, 'mod2') + mod2.write('class C(object):\n pass\n') + mod = testutils.create_module(self.project, 'mod') + +From 8e9667d3318f2846362b8a3c350a9d27d7222818 Mon Sep 17 00:00:00 2001 +From: Matej Cepl +Date: Thu, 12 Feb 2015 01:12:15 +0100 +Subject: [PATCH 2/2] limit socket connections to localhost + +--- + rope/base/oi/doa.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/rope/base/oi/doa.py b/rope/base/oi/doa.py +index 1b2a00f..74bb91b 100644 +--- a/rope/base/oi/doa.py ++++ b/rope/base/oi/doa.py +@@ -113,7 +113,7 @@ def __init__(self): + self.data_port = 3037 + while self.data_port < 4000: + try: +- self.server_socket.bind(('', self.data_port)) ++ self.server_socket.bind(('127.0.0.1', self.data_port)) + break + except socket.error: + self.data_port += 1 diff --git a/python-rope.changes b/python-rope.changes index b8849da..e90547b 100644 --- a/python-rope.changes +++ b/python-rope.changes @@ -1,3 +1,13 @@ +------------------------------------------------------------------- +Wed Feb 18 17:05:54 UTC 2015 - jmatejek@suse.com + +- update to version 0.10.2 + * new maintainer revives project + * accumulated bugfixes + * better test coverage and all tests pass +- disable dynamic object analysis by default, as it is a security risk + (CVE-2014-3539-disable-doa.patch, CVE-2014-3539, boo#916890) + ------------------------------------------------------------------- Wed Jun 6 11:07:01 UTC 2012 - saschpe@suse.de diff --git a/python-rope.spec b/python-rope.spec index 76fe7e6..c2f4558 100644 --- a/python-rope.spec +++ b/python-rope.spec @@ -1,7 +1,7 @@ # # spec file for package python-rope # -# Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,37 +17,35 @@ Name: python-rope -Version: 0.9.4 +Version: 0.10.2 Release: 0 Summary: A python refactoring library License: GPL-2.0+ Group: Development/Languages/Python -Url: http://rope.sf.net/ +Url: https://github.com/python-rope/rope Source: http://pypi.python.org/packages/source/r/rope/rope-%{version}.tar.gz +Patch0: CVE-2014-3539-disable-doa.patch BuildRequires: python-devel BuildRoot: %{_tmppath}/%{name}-%{version}-build -%if 0%{?suse_version} && 0%{?suse_version} <= 1110 -%{!?python_sitelib: %global python_sitelib %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} -%else BuildArch: noarch -%endif %description Rope is a python refactoring library. %prep %setup -q -n rope-%{version} +%patch0 -p1 %build python2 setup.py build %install python2 setup.py install --prefix=%{_prefix} --root=%{buildroot} -rm -rf %{buildroot}/%{py_sitedir}/python-rope/ropetest/ +rm -rf %{buildroot}/%{python_sitlib}/python-rope/ropetest/ %files %defattr(-,root,root,-) -%doc COPYING README.txt docs/ -%python_sitelib/ +%doc COPYING README.rst docs/ +%{python_sitelib}/ %changelog diff --git a/rope-0.10.2.tar.gz b/rope-0.10.2.tar.gz new file mode 100644 index 0000000..e316b50 --- /dev/null +++ b/rope-0.10.2.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fffca108c0d6a711121ce11fed286f4ddc5791c7a6c3f079221a9303d1ddb465 +size 221523 diff --git a/rope-0.9.4.tar.gz b/rope-0.9.4.tar.gz deleted file mode 100644 index 89dfb80..0000000 --- a/rope-0.9.4.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2dc0342604851d8fbdafa198172eab5da7ed422759016669056181e21c54a6ba -size 221516