`pickle.Unpickler`: add hook to intercept `REDUCE` calls
@serhiy-storchaka 已经在做这个了。
开始于 2026年7月9日。
- 主要语言
- Python
- 星标
- 77.2k
- 派生
- 35.9k
- 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 还没有评估数据。