Skip to content

Instantly share code, notes, and snippets.

@mleinart
Last active December 21, 2015 09:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mleinart/6285953 to your computer and use it in GitHub Desktop.
Save mleinart/6285953 to your computer and use it in GitHub Desktop.
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment