From 02969c90d3b0bb2c5ea84cc22d4e4cdbd7963489 Mon Sep 17 00:00:00 2001 From: Grant Murphy Date: Wed, 23 Jul 2014 10:59:46 +1000 Subject: [PATCH] Store suds client library cache at a secure location The default cache implementation stores pickled objects to a predictable path in /tmp. This can be used by a local attacker to redirect SOAP requests via symlinks or run a privilege escalation / code execution attack via a pickle exploit. A fix for this does not currently exist in upstream release of suds. As a temporary measure we should explictly create the suds cache directory in a safe manner. For more information refer to: CVE-2013-2217 Change-Id: I3537bd26bbcc1d6d318f9da7c24c02bd4233526d Closes-bug: #1341954 --- oslo/vmware/service.py | 15 ++++++++++++++- tests/test_service.py | 10 ++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/oslo/vmware/service.py b/oslo/vmware/service.py index 92fadb8..5839a70 100644 --- a/oslo/vmware/service.py +++ b/oslo/vmware/service.py @@ -19,6 +19,8 @@ Common classes that provide access to vSphere services. import httplib import logging +import shutil +import tempfile import urllib2 import netaddr @@ -79,11 +81,22 @@ class Service(object): self.soap_url = soap_url LOG.debug("Creating suds client with soap_url='%s' and wsdl_url='%s'", self.soap_url, self.wsdl_url) + + self._suds_cache_dir = tempfile.mkdtemp(prefix="suds-cache") + cache = suds.cache.FileCache(location=self._suds_cache_dir) self.client = suds.client.Client(self.wsdl_url, location=self.soap_url, - plugins=[ServiceMessagePlugin()]) + plugins=[ServiceMessagePlugin()], + cache=cache) self._service_content = None + def __del__(self): + try: + shutil.rmtree(self._suds_cache_dir) + except OSError as e: + LOG.info("Failed to cleanup suds cache: %s", self._suds_cache_dir) + LOG.debug(e) + @staticmethod def build_base_url(protocol, host, port): proto_str = '%s://' % protocol diff --git a/tests/test_service.py b/tests/test_service.py index 573772a..a54489c 100644 --- a/tests/test_service.py +++ b/tests/test_service.py @@ -14,6 +14,7 @@ # under the License. import httplib +import os import urllib2 import mock @@ -288,3 +289,12 @@ class ServiceTest(base.TestCase): cookie.value = 'xyz' svc_obj.client.options.transport.cookiejar = [cookie] self.assertIsNone(svc_obj.get_http_cookie()) + + def test_suds_client_cache_cleanup(self): + def limit_scope(): + s = service.Service() + path = s._suds_cache_dir + assert(os.path.exists(path)) + return path + cache_dir = limit_scope() + assert(not os.path.exists(cache_dir)) -- 1.9.3