[kupfer] puid: Only reconstruct SerializedObjects using loaded modules



commit d751d6c647b84df6b735fb1391ee28565db49184
Author: Ulrik Sverdrup <ulrik sverdrup gmail com>
Date:   Sat Jan 23 02:26:19 2010 +0100

    puid: Only reconstruct SerializedObjects using loaded modules
    
    We customize the Unpickler so that it refuses load any new modules at
    all.
    
    What we want to do is limit restoration of objects to only those from
    plugins already loaded. However this will not have effect until the
    modified plugin scheme is merged.

 kupfer/puid.py |   51 +++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 47 insertions(+), 4 deletions(-)
---
diff --git a/kupfer/puid.py b/kupfer/puid.py
index ffbefb3..fda399d 100644
--- a/kupfer/puid.py
+++ b/kupfer/puid.py
@@ -5,20 +5,63 @@ Persistent Globally Unique Indentifiers for KupferObjects.
 from __future__ import with_statement
 
 import contextlib
+import cPickle as pickle
+import sys
 
 try:
-	import cPickle as pickle
+	from cStringIO import StringIO
 except ImportError:
-	import pickle
+	from StringIO import StringIO
 
 from kupfer import pretty
-
 from kupfer.core import actioncompat
 from kupfer.core import qfurl
 from kupfer.core.sources import GetSourceController
 
+__all__ = [
+	"SerializedObject", "SERIALIZABLE_ATTRIBUTE",
+	"resolve_unique_id", "resolve_action_id", "get_unique_id", "is_reference",
+]
+
+
 SERIALIZABLE_ATTRIBUTE = "serilizable"
 
+"""
+SerializedObject is a saved representation of a KupferObject, i.e. a
+data model user-level object.
+
+We unpickle SerializedObjects in an especially conservative way: new
+module loading is always refused; this way, we avoid loading parts of
+the program that we didn't wish to activate.
+
+The implementation with Pure-Python pickle would look like::
+
+	class ConservativeUnpickler (pickle.Unpickler):
+		"An Unpickler that refuses to import new modules"
+		def find_class(self, module, name):
+			if module not in sys.modules:
+				raise ValueError("Plugin %s is not loaded" % module)
+			return pickle.Unpickler.find_class(self, module, name)
+
+		@classmethod
+		def loads(cls, pickledata):
+			unpickler = cls(StringIO(pickledata))
+			return unpickler.load()
+
+"""
+
+def _conservative_find_global(module, name):
+	if module not in sys.modules:
+		raise pickle.UnpicklingError("Refusing to load module %s" % module)
+	return getattr(sys.modules[module], name)
+
+def conservative_loads(pickledata):
+	"Unpickle, but refuse to import new modules"
+	unpickler = pickle.Unpickler(StringIO(pickledata))
+	unpickler.find_global = _conservative_find_global
+	return unpickler.load()
+
+
 class SerializedObject (object):
 	# treat the serilizable attribute as a version number, defined on the class
 	def __init__(self, obj):
@@ -28,7 +71,7 @@ class SerializedObject (object):
 		return (isinstance(other, type(self)) and self.data == other.data and
 		        self.version == other.version)
 	def reconstruct(self):
-		obj = pickle.loads(self.data)
+		obj = conservative_loads(self.data)
 		if self.version != getattr(obj, SERIALIZABLE_ATTRIBUTE):
 			raise ValueError("Version mismatch for reconstructed %s" % obj)
 		return obj



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]