@@ -93,7 +93,81 @@ def deserialize(_bytes):
9393 return _bytes
9494
9595
96- deserialize_blacklist = [b'eval' , b'execfile' , b'compile' , b'system' , b'popen' ,
96+ class WhitelistPickleSerdes (ABCSerdes ):
97+ @staticmethod
98+ def serialize (_obj ):
99+ return p_dumps (_obj )
100+
101+ @staticmethod
102+ def deserialize (_bytes ):
103+ bytes_security_check (_bytes )
104+ return RestrictedUnpickler (io .BytesIO (_bytes )).load ()
105+
106+ class _DeserializeWhitelist :
107+ loaded = False
108+ deserialize_whitelist = {}
109+ deserialize_glob_whitelist = set ()
110+
111+
112+ @classmethod
113+ def get_whitelist_glob (cls ):
114+ if not cls .loaded :
115+ cls .load_deserialize_whitelist ()
116+ return cls .deserialize_glob_whitelist
117+
118+ @classmethod
119+ def get_whitelist (cls ):
120+ if not cls .loaded :
121+ cls .load_deserialize_whitelist ()
122+ return cls .deserialize_whitelist
123+
124+ @classmethod
125+ def get_whitelist_path (cls ):
126+ import os .path
127+
128+ return os .path .abspath (
129+ os .path .join (
130+ __file__ ,
131+ os .path .pardir ,
132+ os .path .pardir ,
133+ os .path .pardir ,
134+ os .path .pardir ,
135+ os .path .pardir ,
136+ "conf" ,
137+ "whitelist.json" ,
138+ )
139+ )
140+
141+ @classmethod
142+ def load_deserialize_whitelist (cls ):
143+ import json
144+ with open (cls .get_whitelist_path ()) as f :
145+ for k , v in json .load (f ).items ():
146+ if k .endswith ("*" ):
147+ cls .deserialize_glob_whitelist .add (k [:- 1 ])
148+ else :
149+ cls .deserialize_whitelist [k ] = set (v )
150+ cls .loaded = True
151+
152+ class RestrictedUnpickler (pickle .Unpickler ):
153+
154+ def _load (self , module , name ):
155+ try :
156+ return super ().find_class (module , name )
157+ except :
158+ return getattr (importlib .import_module (module ), name )
159+
160+
161+ def find_class (self , module , name ):
162+ if name in _DeserializeWhitelist .get_whitelist ().get (module , set ()):
163+ return self ._load (module , name )
164+ else :
165+ for m in _DeserializeWhitelist .get_whitelist_glob ():
166+ if module .startswith (m ):
167+ return self ._load (module , name )
168+ raise pickle .UnpicklingError (f"forbidden unpickle class { module } { name } " )
169+
170+ deserialize_blacklist = {b'eval' , b'execfile' , b'compile' , b'system' , b'popen' ,
97171 b'popen2' , b'popen3' ,
98172 b'popen4' , b'fdopen' , b'tmpfile' , b'fchmod' , b'fchown' ,
99173 b'openpty' ,
@@ -116,7 +190,8 @@ def deserialize(_bytes):
116190 b'listdir' , b'opendir' , b'timeit' , b'repeat' ,
117191 b'call_tracing' , b'interact' , b'compile_command' ,
118192 b'spawn' ,
119- b'fileopen' ]
193+ b'fileopen' ,
194+ b'getattr' }
120195
121196future_blacklist = [b'read' , b'dup' , b'fork' , b'walk' , b'file' , b'move' ,
122197 b'link' , b'kill' , b'open' , b'pipe' ]
0 commit comments