[graphite-web/el5] Move back to 0.9.10 to patch for CVE-2013-5093
Jonathan Steffan
jsteffan at fedoraproject.org
Fri Sep 20 00:22:10 UTC 2013
commit 203eb4da795f5751df6b3b3e4faefc582ebcfdc1
Author: Jonathan Steffan <jsteffan at fedoraproject.org>
Date: Thu Sep 19 18:21:01 2013 -0600
Move back to 0.9.10 to patch for CVE-2013-5093
graphite-web-0.9.10-CVE-2013-5093.patch | 207 ++++++++++++++++++++++++++++++
graphite-web-0.9.10-fhs-thirdparty.patch | 185 ++++++++++++++++++++++++++
graphite-web-0.9.12-fhs-thirdparty.patch | 162 -----------------------
graphite-web.spec | 25 ++--
sources | 2 +-
5 files changed, 405 insertions(+), 176 deletions(-)
---
diff --git a/graphite-web-0.9.10-CVE-2013-5093.patch b/graphite-web-0.9.10-CVE-2013-5093.patch
new file mode 100644
index 0000000..e946568
--- /dev/null
+++ b/graphite-web-0.9.10-CVE-2013-5093.patch
@@ -0,0 +1,207 @@
+diff --git a/webapp/graphite/remote_storage.py b/webapp/graphite/remote_storage.py
+index b33250f..1f8a578 100644
+--- a/webapp/graphite/remote_storage.py
++++ b/webapp/graphite/remote_storage.py
+@@ -5,11 +5,7 @@ from urllib import urlencode
+ from django.core.cache import cache
+ from django.conf import settings
+ from graphite.render.hashing import compactHash
+-
+-try:
+- import cPickle as pickle
+-except ImportError:
+- import pickle
++from graphite.util import unpickle
+
+
+
+@@ -79,7 +75,7 @@ class FindRequest:
+ response = self.connection.getresponse()
+ assert response.status == 200, "received error response %s - %s" % (response.status, response.reason)
+ result_data = response.read()
+- results = pickle.loads(result_data)
++ results = unpickle.loads(result_data)
+
+ except:
+ self.store.fail()
+@@ -126,7 +122,7 @@ class RemoteNode:
+ assert response.status == 200, "Failed to retrieve remote data: %d %s" % (response.status, response.reason)
+ rawData = response.read()
+
+- seriesList = pickle.loads(rawData)
++ seriesList = unpickle.loads(rawData)
+ assert len(seriesList) == 1, "Invalid result: seriesList=%s" % str(seriesList)
+ series = seriesList[0]
+
+diff --git a/webapp/graphite/render/datalib.py b/webapp/graphite/render/datalib.py
+index b5f7b83..3b697c7 100644
+--- a/webapp/graphite/render/datalib.py
++++ b/webapp/graphite/render/datalib.py
+@@ -19,6 +19,7 @@ from django.conf import settings
+ from graphite.logger import log
+ from graphite.storage import STORE, LOCAL_STORE
+ from graphite.render.hashing import ConsistentHashRing
++from graphite.util import unpickle
+
+ try:
+ import cPickle as pickle
+@@ -173,7 +174,7 @@ class CarbonLinkPool:
+ len_prefix = recv_exactly(conn, 4)
+ body_size = struct.unpack("!L", len_prefix)[0]
+ body = recv_exactly(conn, body_size)
+- return pickle.loads(body)
++ return unpickle.loads(body)
+
+
+ # Utilities
+diff --git a/webapp/graphite/render/views.py b/webapp/graphite/render/views.py
+index e367f8c..6d10799 100644
+--- a/webapp/graphite/render/views.py
++++ b/webapp/graphite/render/views.py
+@@ -24,7 +24,7 @@ try:
+ except ImportError:
+ import pickle
+
+-from graphite.util import getProfileByUsername, json
++from graphite.util import getProfileByUsername, json, unpickle
+ from graphite.remote_storage import HTTPConnectionWithTimeout
+ from graphite.logger import log
+ from graphite.render.evaluator import evaluateTarget
+@@ -303,7 +303,7 @@ def renderLocalView(request):
+ optionsPickle = reqParams.read()
+ reqParams.close()
+ graphClass = GraphTypes[graphType]
+- options = pickle.loads(optionsPickle)
++ options = unpickle.loads(optionsPickle)
+ image = doImageRender(graphClass, options)
+ log.rendering("Delegated rendering request took %.6f seconds" % (time() - start))
+ return buildResponse(image)
+diff --git a/webapp/graphite/storage.py b/webapp/graphite/storage.py
+index e765189..5863c2d 100644
+--- a/webapp/graphite/storage.py
++++ b/webapp/graphite/storage.py
+@@ -1,8 +1,10 @@
+ import os, time, fnmatch, socket, errno
++from django.conf import settings
+ from os.path import isdir, isfile, join, exists, splitext, basename, realpath
+ import whisper
+ from graphite.remote_storage import RemoteStore
+ from django.conf import settings
++from graphite.util import unpickle
+
+ try:
+ import rrdtool
+@@ -307,7 +309,7 @@ class WhisperFile(Leaf):
+
+ if exists(context_path):
+ fh = open(context_path, 'rb')
+- context_data = pickle.load(fh)
++ context_data = unpickle.load(fh)
+ fh.close()
+ else:
+ context_data = {}
+diff --git a/webapp/graphite/util.py b/webapp/graphite/util.py
+index ada524d..54f425b 100644
+--- a/webapp/graphite/util.py
++++ b/webapp/graphite/util.py
+@@ -12,6 +12,18 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License."""
+
++try:
++ import cPickle as pickle
++ USING_CPICKLE = True
++except:
++ import pickle
++ USING_CPICKLE = False
++
++try:
++ from cStringIO import StringIO
++except ImportError:
++ from StringIO import StringIO
++
+ from django.core.exceptions import ObjectDoesNotExist
+ from django.contrib.auth.models import User
+ from graphite.account.models import Profile
+@@ -65,3 +77,52 @@ except Profile.DoesNotExist:
+ log.info("Default profile does not exist, creating it...")
+ defaultProfile = Profile(user=defaultUser)
+ defaultProfile.save()
++
++# This whole song & dance is due to pickle being insecure
++# The SafeUnpickler classes were largely derived from
++# http://nadiana.com/python-pickle-insecure
++# This code also lives in carbon.util
++if USING_CPICKLE:
++ class SafeUnpickler(object):
++ PICKLE_SAFE = {
++ 'copy_reg': set(['_reconstructor']),
++ '__builtin__': set(['object']),
++ }
++
++ @classmethod
++ def find_class(cls, module, name):
++ if not module in cls.PICKLE_SAFE:
++ raise pickle.UnpicklingError('Attempting to unpickle unsafe module %s' % module)
++ __import__(module)
++ mod = sys.modules[module]
++ if not name in cls.PICKLE_SAFE[module]:
++ raise pickle.UnpicklingError('Attempting to unpickle unsafe class %s' % name)
++ return getattr(mod, name)
++
++ @classmethod
++ def loads(cls, pickle_string):
++ pickle_obj = pickle.Unpickler(StringIO(pickle_string))
++ pickle_obj.find_global = cls.find_class
++ return pickle_obj.load()
++
++else:
++ class SafeUnpickler(pickle.Unpickler):
++ PICKLE_SAFE = {
++ 'copy_reg': set(['_reconstructor']),
++ '__builtin__': set(['object']),
++ }
++
++ def find_class(self, module, name):
++ if not module in self.PICKLE_SAFE:
++ raise pickle.UnpicklingError('Attempting to unpickle unsafe module %s' % module)
++ __import__(module)
++ mod = sys.modules[module]
++ if not name in self.PICKLE_SAFE[module]:
++ raise pickle.UnpicklingError('Attempting to unpickle unsafe class %s' % name)
++ return getattr(mod, name)
++
++ @classmethod
++ def loads(cls, pickle_string):
++ return cls(StringIO(pickle_string)).load()
++
++unpickle = SafeUnpickler
+diff --git a/webapp/graphite/whitelist/views.py b/webapp/graphite/whitelist/views.py
+index 5baec8d..36374d7 100644
+--- a/webapp/graphite/whitelist/views.py
++++ b/webapp/graphite/whitelist/views.py
+@@ -13,14 +13,12 @@ See the License for the specific language governing permissions and
+ limitations under the License."""
+
+ import os
+-try:
+- import cPickle as pickle
+-except ImportError:
+- import pickle
+ from random import randint
+ from django.http import HttpResponse
+ from django.conf import settings
+
++from graphite.util import unpickle
++
+
+ def add(request):
+ metrics = set( request.POST['metrics'].split() )
+@@ -43,7 +41,7 @@ def show(request):
+
+ def load_whitelist():
+ fh = open(settings.WHITELIST_FILE, 'rb')
+- whitelist = pickle.load(fh)
++ whitelist = unpickle.load(fh)
+ fh.close()
+ return whitelist
diff --git a/graphite-web-0.9.10-fhs-thirdparty.patch b/graphite-web-0.9.10-fhs-thirdparty.patch
new file mode 100644
index 0000000..7f0535a
--- /dev/null
+++ b/graphite-web-0.9.10-fhs-thirdparty.patch
@@ -0,0 +1,185 @@
+diff -up ./check-dependencies.py.orig ./check-dependencies.py
+--- ./check-dependencies.py.orig 2012-05-31 00:28:54.000000000 -0600
++++ ./check-dependencies.py 2012-11-24 14:09:50.040701191 -0700
+@@ -58,6 +58,19 @@ except:
+ django = None
+ fatal += 1
+
++# Test for pytz
++try:
++ import pytz
++except:
++ print "[FATAL] Unable to import the 'pytz' module, do you have pytz module installed for python %s?\n" % py_version
++ fatal += 1
++
++# Test for pyparsing
++try:
++ import pyparsing
++except:
++ print "[FATAL] Unable to import the 'pyparsing' module, do you have pyparsing module installed for python %s?\n" % py_version
++ fatal += 1
+
+ # Test for django-tagging
+ try:
+diff -up ./conf/graphite.wsgi.example.orig ./conf/graphite.wsgi.example
+--- ./conf/graphite.wsgi.example.orig 2012-05-31 00:28:54.000000000 -0600
++++ ./conf/graphite.wsgi.example 2012-11-24 14:10:08.310633299 -0700
+@@ -1,5 +1,5 @@
+ import os, sys
+-sys.path.append('/opt/graphite/webapp')
++sys.path.append('/usr/share/graphite/webapp')
+ os.environ['DJANGO_SETTINGS_MODULE'] = 'graphite.settings'
+
+ import django.core.handlers.wsgi
+diff -up ./MANIFEST.in.orig ./MANIFEST.in
+--- ./MANIFEST.in.orig 2012-05-31 00:28:54.000000000 -0600
++++ ./MANIFEST.in 2012-11-24 14:09:50.039701194 -0700
+@@ -5,7 +5,6 @@ include check-dependencies.py
+ include examples/*
+ include conf/*.example
+ include webapp/graphite/local_settings.py.example
+-include webapp/graphite/thirdparty/pytz/pytz-LICENSE.txt
+ recursive-include distro/ *
+ recursive-include webapp/graphite/ *.html
+ recursive-include webapp/content/ *
+diff -up ./setup.cfg.orig ./setup.cfg
+--- ./setup.cfg.orig 2012-11-24 14:09:51.776694909 -0700
++++ ./setup.cfg 2012-11-24 14:10:08.311633295 -0700
+@@ -1,6 +1,7 @@
+ [install]
+-prefix = /opt/graphite
+-install-lib = %(prefix)s/webapp
++#prefix = /opt/graphite
++#install-lib = %(prefix)s/webapp
++install-data = /usr/share/graphite
+
+ [bdist_rpm]
+ requires = Django => 1.1.4
+diff -up ./setup.py.orig ./setup.py
+--- ./setup.py.orig 2012-11-24 14:09:51.776694909 -0700
++++ ./setup.py 2012-11-24 14:10:08.312633291 -0700
+@@ -58,6 +58,7 @@ setup(
+ package_data={'graphite' :
+ ['templates/*', 'local_settings.py.example']},
+ scripts=glob('bin/*'),
+- data_files=webapp_content.items() + storage_dirs + conf_files + examples,
++ #data_files=webapp_content.items() + storage_dirs + conf_files + examples,
++ data_files=webapp_content.items(),
+ **setup_kwargs
+ )
+diff -up ./webapp/graphite/cli/parser.py.orig ./webapp/graphite/cli/parser.py
+--- ./webapp/graphite/cli/parser.py.orig 2012-05-31 00:28:54.000000000 -0600
++++ ./webapp/graphite/cli/parser.py 2012-11-24 14:09:51.777694906 -0700
+@@ -12,7 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ See the License for the specific language governing permissions and
+ limitations under the License."""
+
+-from graphite.thirdparty.pyparsing import *
++from pyparsing import *
+
+ grammar = Forward()
+
+diff -up ./webapp/graphite/local_settings.py.example.orig ./webapp/graphite/local_settings.py.example
+--- ./webapp/graphite/local_settings.py.example.orig 2012-05-31 00:28:54.000000000 -0600
++++ ./webapp/graphite/local_settings.py.example 2012-11-24 14:10:08.313633288 -0700
+@@ -43,29 +43,29 @@
+ #####################################
+ # Change only GRAPHITE_ROOT if your install is merely shifted from /opt/graphite
+ # to somewhere else
+-#GRAPHITE_ROOT = '/opt/graphite'
++GRAPHITE_ROOT = '/usr/share/graphite'
+
+ # Most installs done outside of a separate tree such as /opt/graphite will only
+ # need to change these three settings. Note that the default settings for each
+ # of these is relative to GRAPHITE_ROOT
+-#CONF_DIR = '/opt/graphite/conf'
+-#STORAGE_DIR = '/opt/graphite/storage'
+-#CONTENT_DIR = '/opt/graphite/webapp/content'
++CONF_DIR = '/etc/graphite-web'
++STORAGE_DIR = '/var/lib/graphite-web'
++CONTENT_DIR = '/usr/share/graphite/webapp/content'
+
+ # To further or fully customize the paths, modify the following. Note that the
+ # default settings for each of these are relative to CONF_DIR and STORAGE_DIR
+ #
+ ## Webapp config files
+-#DASHBOARD_CONF = '/opt/graphite/conf/dashboard.conf'
+-#GRAPHTEMPLATES_CONF = '/opt/graphite/conf/graphTemplates.conf'
++#DASHBOARD_CONF = '/etc/graphite-web/dashboard.conf'
++#GRAPHTEMPLATES_CONF = '/etc/graphite-web/graphTemplates.conf'
+
+ ## Data directories
+ # NOTE: If any directory is unreadable in DATA_DIRS it will break metric browsing
+-#WHISPER_DIR = '/opt/graphite/storage/whisper'
+-#RRD_DIR = '/opt/graphite/storage/rrd'
+-#DATA_DIRS = [WHISPER_DIR, RRD_DIR] # Default: set from the above variables
+-#LOG_DIR = '/opt/graphite/storage/log/webapp'
+-#INDEX_FILE = '/opt/graphite/storage/index' # Search index file
++WHISPER_DIR = '/var/lib/carbon/whisper/'
++RRD_DIR = '/var/lib/carbon/rrd'
++DATA_DIRS = [WHISPER_DIR, RRD_DIR] # Default: set from the above variables
++LOG_DIR = '/var/log/graphite-web/'
++INDEX_FILE = '/var/lib/graphite-web/index' # Search index file
+
+
+ #####################################
+diff -up ./webapp/graphite/render/attime.py.orig ./webapp/graphite/render/attime.py
+--- ./webapp/graphite/render/attime.py.orig 2012-05-31 00:28:54.000000000 -0600
++++ ./webapp/graphite/render/attime.py 2012-11-24 14:09:51.777694906 -0700
+@@ -16,11 +16,7 @@ from datetime import datetime,timedelta
+ from time import daylight
+ from django.conf import settings
+
+-try: # See if there is a system installation of pytz first
+- import pytz
+-except ImportError: # Otherwise we fall back to Graphite's bundled version
+- from graphite.thirdparty import pytz
+-
++import pytz
+
+ months = ['jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec']
+ weekdays = ['sun','mon','tue','wed','thu','fri','sat']
+diff -up ./webapp/graphite/render/glyph.py.orig ./webapp/graphite/render/glyph.py
+--- ./webapp/graphite/render/glyph.py.orig 2012-05-31 00:28:54.000000000 -0600
++++ ./webapp/graphite/render/glyph.py 2012-11-24 14:09:51.779694900 -0700
+@@ -22,10 +22,7 @@ from graphite.render.datalib import Time
+ from graphite.util import json
+
+
+-try: # See if there is a system installation of pytz first
+- import pytz
+-except ImportError: # Otherwise we fall back to Graphite's bundled version
+- from graphite.thirdparty import pytz
++import pytz
+
+ INFINITY = float('inf')
+
+diff -up ./webapp/graphite/render/grammar.py.orig ./webapp/graphite/render/grammar.py
+--- ./webapp/graphite/render/grammar.py.orig 2012-05-31 00:28:54.000000000 -0600
++++ ./webapp/graphite/render/grammar.py 2012-11-24 14:09:51.779694900 -0700
+@@ -1,4 +1,4 @@
+-from graphite.thirdparty.pyparsing import *
++from pyparsing import *
+
+ ParserElement.enablePackrat()
+ grammar = Forward()
+diff -up ./webapp/graphite/settings.py.orig ./webapp/graphite/settings.py
+--- ./webapp/graphite/settings.py.orig 2012-05-31 14:30:23.000000000 -0600
++++ ./webapp/graphite/settings.py 2012-11-24 14:09:51.780694897 -0700
+@@ -31,7 +31,6 @@ JAVASCRIPT_DEBUG = False
+ WEB_DIR = dirname( abspath(__file__) )
+ WEBAPP_DIR = dirname(WEB_DIR)
+ GRAPHITE_ROOT = dirname(WEBAPP_DIR)
+-THIRDPARTY_DIR = join(WEB_DIR,'thirdparty')
+ # Initialize additional path variables
+ # Defaults for these are set after local_settings is imported
+ CONTENT_DIR = ''
+@@ -50,8 +49,6 @@ DATA_DIRS = []
+ CLUSTER_SERVERS = []
+
+ sys.path.insert(0, WEBAPP_DIR)
+-# Allow local versions of the libs shipped in thirdparty to take precedence
+-sys.path.append(THIRDPARTY_DIR)
+
+ # Memcache settings
+ MEMCACHE_HOSTS = []
diff --git a/graphite-web.spec b/graphite-web.spec
index 4e1449d..297625f 100644
--- a/graphite-web.spec
+++ b/graphite-web.spec
@@ -1,19 +1,20 @@
%{!?python_sitelib: %global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")}
Name: graphite-web
-Version: 0.9.12
-Release: 2%{?dist}
+Version: 0.9.10
+Release: 9%{?dist}
Summary: A Django webapp for enterprise scalable realtime graphing
Group: Applications/Internet
License: ASL 2.0
URL: https://launchpad.net/graphite/
-Source0: https://github.com/graphite-project/graphite-web/archive/0.9.12.tar.gz#/%{name}-%{version}.tar.gz
+Source0: https://github.com/downloads/graphite-project/graphite-web/graphite-web-0.9.10.tar.gz
Source1: graphite-web-vhost.conf
Source2: graphite-web-README.fedora
Source3: graphite-web-logrotate.fedora
Source4: graphite-web-README.selinux
-Patch0: graphite-web-0.9.12-fhs-thirdparty.patch
+Patch0: graphite-web-0.9.10-fhs-thirdparty.patch
+Patch1: graphite-web-0.9.10-CVE-2013-5093.patch
BuildRoot: %{_tmppath}/graphite-web-%{version}-%{release}-root-%(%{__id_u} -n)
BuildArch: noarch
@@ -22,9 +23,9 @@ Requires: python-whisper, mod_wsgi, pytz, pyparsing, python-simplejson
Requires: dejavu-sans-fonts, dejavu-serif-fonts, pycairo, django-tagging
%if 0%{?fedora} <= 17
-Requires: python-sqlite2, Django >= 1.3
+Requires: python-sqlite2, Django
%else
-Requires: python-django >= 1.3
+Requires: python-django
%endif
@@ -62,7 +63,9 @@ SELinux labeling for graphite files.
%setup -q -n graphite-web-%{version}
# Patch for Filesystem Hierarchy Standard
# Remove thridparty libs
+# https://github.com/hggh/graphite-web-upstream/commit/47361a2707f904a8b817ca96deeddabcdbaaa534.patch
%patch0 -p1
+%patch1 -p1
%{__install} -m 644 %{SOURCE2} README.fedora
%{__install} -m 644 %{SOURCE4} README.selinux
@@ -139,17 +142,13 @@ fi
%doc README.selinux
%changelog
-* Tue Sep 17 2013 Jonathan Steffan <jsteffan at fedoraproject.org> - 0.9.12-2
+* Thu Sep 19 2013 Jonathan Steffan <jsteffan at fedoraproject.org> - 0.9.10-9
- Don't ship js/ext/resources/*.swf (RHBZ#1000253)
+- Patch for CVE-2013-5093 (RHBZ#1000060)
-* Mon Sep 02 2013 Jonathan Steffan <jsteffan at fedoraproject.org> - 0.9.12-1
-- Update to 0.9.12
-- Require Django >= 1.3
+* Wed Mar 13 2013 Jonathan Steffan <jsteffan at fedoraproject.org> - 0.9.10-8
- Add EL5 conditional for SELinux policycoreutils
-* Sat Aug 03 2013 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 0.9.10-8
-- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
-
* Wed Mar 13 2013 Jonathan Steffan <jsteffan at fedoraproject.org> - 0.9.10-7
- Update required fonts to actually include fonts (RHBZ#917361)
diff --git a/sources b/sources
index 2110667..0fa30cf 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-c09f19fc0076cbadec64039f161bafc0 graphite-web-0.9.12.tar.gz
+f54bf784139c7aef441f5cc1bc66dab4 graphite-web-0.9.10.tar.gz
More information about the scm-commits
mailing list