`pickle.Unpickler`: add hook to intercept `REDUCE` calls
@serhiy-storchaka 已經在處理了。
開始於 2026年7月9日。
- 主要語言
- Python
- 星號
- 77.2k
- 分支
- 36k
- PR 合併指標
- PR 指標待擷取
描述
Feature or enhancement
Proposal:
I want to pickle and unpickle data that may validly contain types.FunctionType instances, but I want to prevent them from being used in REDUCE opcodes, to protect me from RCEs like REDUCE os.system('firefox https://www.youtube.com/watch?v=dQw4w9WgXcQ').
The traditional conservative approach is to use an allowlist, e.g.:
class SafeUnpickler(pickle.Unpickler):
def find_class(self, module, name):
obj = super().find_class(module, name)
if not known_to_be_safe(obj):
raise pickle.UnpicklingError(f"unsupported symbol '{module}.{name}'")
return obj
However, find_class is applied when a GLOBAL/STACK_GLOBAL opcode is executed, before the interpreter knows whether the symbol will be used as a value or passed to REDUCE. I want to permit pickling of any function, including os.system; I just don't want to allow passing it to REDUCE.
So, what I really want is some sort of hook called at REDUCE time. One concrete proposal:
Ts = TypeVarTuple('Ts')
R = TypeVar('R')
def reconstruct(self, constructor: Callable[[*Ts], R], args: tuple[*Ts]) -> R:
# default impl; overrides may raise UnpicklingError
return constructor(*args)
The safe idiom would be:
known_safe_classes = (SomeClass, OtherClass)
def reconstruct(self, constructor: Callable[[*Ts], R], args: tuple[*Ts]) -> R:
if not isinstance(constructor, type):
# prevent e.g. os.system RCE
raise UnpicklingError(...)
if not issubclass(constructor, known_safe_classes):
# prevent e.g. subprocess.Popen RCE
raise UnpicklingError(...)
return constructor(*args)
Dismissed alternatives:
- I can solve my problem by prohibiting functions in
find_class, and instead providing a custom serialization forFunctionTypethroughpersistent_id/persistent_load, but this is unfortunate since I need to re-implement serialization from scratch of a type that is already supported natively. - I can solve my problem by subclassing the undocumented pure-python
pickle._Unpicklerinstead ofpickle.Unpickler, and overriding the undocumentedload_reduce(which cPickle's Unpickler does not honor). This is undocumented and slow.
Has this already been discussed elsewhere?
No response given
Links to previous discussion of this feature:
No response
貢獻指南
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
評估
這個 Issue 還沒有評估資料。