Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:15.2
python-PyYAML
pyyaml-5.1.2.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File pyyaml-5.1.2.patch of Package python-PyYAML
diff --git a/lib/yaml/constructor.py b/lib/yaml/constructor.py index 516dad1..a54758d 100644 --- a/lib/yaml/constructor.py +++ b/lib/yaml/constructor.py @@ -33,6 +33,14 @@ class BaseConstructor(object): # If there are more documents available? return self.check_node() + def check_state_key(self, key): + """Block special attributes/methods from being set in a newly created + object, to prevent user-controlled methods from being called during + deserialization""" + if self.get_state_keys_blacklist_regexp().match(key): + raise ConstructorError(None, None, + "blacklisted key '%s' in instance state found" % (key,), None) + def get_data(self): # Construct and return the next document. if self.check_node(): @@ -471,6 +479,16 @@ SafeConstructor.add_constructor(None, SafeConstructor.construct_undefined) class FullConstructor(SafeConstructor): + # 'extend' is blacklisted because it is used by + # construct_python_object_apply to add `listitems` to a newly generate + # python instance + def get_state_keys_blacklist(self): + return ['^extend$', '^__.*__$'] + + def get_state_keys_blacklist_regexp(self): + if not hasattr(self, 'state_keys_blacklist_regexp'): + self.state_keys_blacklist_regexp = re.compile('(' + '|'.join(self.get_state_keys_blacklist()) + ')') + return self.state_keys_blacklist_regexp def construct_python_str(self, node): return self.construct_scalar(node).encode('utf-8') @@ -566,7 +584,7 @@ class FullConstructor(SafeConstructor): else: return cls(*args, **kwds) - def set_python_instance_state(self, instance, state): + def set_python_instance_state(self, instance, state, unsafe=False): if hasattr(instance, '__setstate__'): instance.__setstate__(state) else: @@ -574,10 +592,15 @@ class FullConstructor(SafeConstructor): if isinstance(state, tuple) and len(state) == 2: state, slotstate = state if hasattr(instance, '__dict__'): + if not unsafe and state: + for key in state.keys(): + self.check_state_key(key) instance.__dict__.update(state) elif state: slotstate.update(state) for key, value in slotstate.items(): + if not unsafe: + self.check_state_key(key) setattr(object, key, value) def construct_python_object(self, suffix, node): @@ -683,10 +706,6 @@ FullConstructor.add_multi_constructor( u'tag:yaml.org,2002:python/object:', FullConstructor.construct_python_object) -FullConstructor.add_multi_constructor( - u'tag:yaml.org,2002:python/object/apply:', - FullConstructor.construct_python_object_apply) - FullConstructor.add_multi_constructor( u'tag:yaml.org,2002:python/object/new:', FullConstructor.construct_python_object_new) @@ -703,6 +722,14 @@ class UnsafeConstructor(FullConstructor): return super(UnsafeConstructor, self).make_python_instance( suffix, node, args, kwds, newobj, unsafe=True) + def set_python_instance_state(self, instance, state): + return super(UnsafeConstructor, self).set_python_instance_state( + instance, state, unsafe=True) + +UnsafeConstructor.add_multi_constructor( + u'tag:yaml.org,2002:python/object/apply:', + UnsafeConstructor.construct_python_object_apply) + # Constructor is same as UnsafeConstructor. Need to leave this in place in case # people have extended it directly. class Constructor(UnsafeConstructor): diff --git a/lib3/yaml/constructor.py b/lib3/yaml/constructor.py index 34fc1ae..40974af 100644 --- a/lib3/yaml/constructor.py +++ b/lib3/yaml/constructor.py @@ -31,6 +31,14 @@ class BaseConstructor: # If there are more documents available? return self.check_node() + def check_state_key(self, key): + """Block special attributes/methods from being set in a newly created + object, to prevent user-controlled methods from being called during + deserialization""" + if self.get_state_keys_blacklist_regexp().match(key): + raise ConstructorError(None, None, + "blacklisted key '%s' in instance state found" % (key,), None) + def get_data(self): # Construct and return the next document. if self.check_node(): @@ -471,6 +479,16 @@ SafeConstructor.add_constructor(None, SafeConstructor.construct_undefined) class FullConstructor(SafeConstructor): + # 'extend' is blacklisted because it is used by + # construct_python_object_apply to add `listitems` to a newly generate + # python instance + def get_state_keys_blacklist(self): + return ['^extend$', '^__.*__$'] + + def get_state_keys_blacklist_regexp(self): + if not hasattr(self, 'state_keys_blacklist_regexp'): + self.state_keys_blacklist_regexp = re.compile('(' + '|'.join(self.get_state_keys_blacklist()) + ')') + return self.state_keys_blacklist_regexp def construct_python_str(self, node): return self.construct_scalar(node) @@ -573,7 +591,7 @@ class FullConstructor(SafeConstructor): else: return cls(*args, **kwds) - def set_python_instance_state(self, instance, state): + def set_python_instance_state(self, instance, state, unsafe=False): if hasattr(instance, '__setstate__'): instance.__setstate__(state) else: @@ -581,10 +599,15 @@ class FullConstructor(SafeConstructor): if isinstance(state, tuple) and len(state) == 2: state, slotstate = state if hasattr(instance, '__dict__'): + if not unsafe and state: + for key in state.keys(): + self.check_state_key(key) instance.__dict__.update(state) elif state: slotstate.update(state) for key, value in slotstate.items(): + if not unsafe: + self.check_state_key(key) setattr(object, key, value) def construct_python_object(self, suffix, node): @@ -694,10 +717,6 @@ FullConstructor.add_multi_constructor( 'tag:yaml.org,2002:python/object:', FullConstructor.construct_python_object) -FullConstructor.add_multi_constructor( - 'tag:yaml.org,2002:python/object/apply:', - FullConstructor.construct_python_object_apply) - FullConstructor.add_multi_constructor( 'tag:yaml.org,2002:python/object/new:', FullConstructor.construct_python_object_new) @@ -714,6 +733,14 @@ class UnsafeConstructor(FullConstructor): return super(UnsafeConstructor, self).make_python_instance( suffix, node, args, kwds, newobj, unsafe=True) + def set_python_instance_state(self, instance, state): + return super(UnsafeConstructor, self).set_python_instance_state( + instance, state, unsafe=True) + +UnsafeConstructor.add_multi_constructor( + 'tag:yaml.org,2002:python/object/apply:', + UnsafeConstructor.construct_python_object_apply) + # Constructor is same as UnsafeConstructor. Need to leave this in place in case # people have extended it directly. class Constructor(UnsafeConstructor): diff --git a/tests/data/myfullloader.subclass_blacklist b/tests/data/myfullloader.subclass_blacklist new file mode 100644 index 0000000..555a2b3 --- /dev/null +++ b/tests/data/myfullloader.subclass_blacklist @@ -0,0 +1,5 @@ +- !!python/object/new:yaml.MappingNode + args: + state: + mymethod: test + wrong_method: test2 diff --git a/tests/data/overwrite-state-new-constructor.loader-error b/tests/data/overwrite-state-new-constructor.loader-error new file mode 100644 index 0000000..8d224f1 --- /dev/null +++ b/tests/data/overwrite-state-new-constructor.loader-error @@ -0,0 +1,5 @@ +- !!python/object/new:yaml.MappingNode + args: + state: + extend: test + __test__: test diff --git a/tests/lib/test_constructor.py b/tests/lib/test_constructor.py index beee7b0..a18d13d 100644 --- a/tests/lib/test_constructor.py +++ b/tests/lib/test_constructor.py @@ -17,7 +17,7 @@ def _make_objects(): global MyLoader, MyDumper, MyTestClass1, MyTestClass2, MyTestClass3, YAMLObject1, YAMLObject2, \ AnObject, AnInstance, AState, ACustomState, InitArgs, InitArgsWithState, \ NewArgs, NewArgsWithState, Reduce, ReduceWithState, MyInt, MyList, MyDict, \ - FixedOffset, today, execute + FixedOffset, today, execute, MyFullLoader class MyLoader(yaml.Loader): pass @@ -213,6 +213,10 @@ def _make_objects(): def dst(self, dt): return datetime.timedelta(0) + class MyFullLoader(yaml.FullLoader): + def get_state_keys_blacklist(self): + return super(MyFullLoader, self).get_state_keys_blacklist() + ['^mymethod$', '^wrong_.*$'] + today = datetime.date.today() def _load_code(expression): @@ -267,6 +271,18 @@ def test_constructor_types(data_filename, code_filename, verbose=False): test_constructor_types.unittest = ['.data', '.code'] +def test_subclass_blacklist_types(data_filename, verbose=False): + _make_objects() + try: + yaml.load(open(data_filename, 'rb').read(), MyFullLoader) + except yaml.YAMLError as exc: + if verbose: + print("%s:" % exc.__class__.__name__, exc) + else: + raise AssertionError("expected an exception") + +test_subclass_blacklist_types.unittest = ['.subclass_blacklist'] + if __name__ == '__main__': import sys, test_constructor sys.modules['test_constructor'] = sys.modules['__main__'] diff --git a/tests/lib3/test_constructor.py b/tests/lib3/test_constructor.py index 427f53c..fb4509e 100644 --- a/tests/lib3/test_constructor.py +++ b/tests/lib3/test_constructor.py @@ -14,7 +14,7 @@ def _make_objects(): global MyLoader, MyDumper, MyTestClass1, MyTestClass2, MyTestClass3, YAMLObject1, YAMLObject2, \ AnObject, AnInstance, AState, ACustomState, InitArgs, InitArgsWithState, \ NewArgs, NewArgsWithState, Reduce, ReduceWithState, MyInt, MyList, MyDict, \ - FixedOffset, today, execute + FixedOffset, today, execute, MyFullLoader class MyLoader(yaml.Loader): pass @@ -200,6 +200,10 @@ def _make_objects(): def dst(self, dt): return datetime.timedelta(0) + class MyFullLoader(yaml.FullLoader): + def get_state_keys_blacklist(self): + return super().get_state_keys_blacklist() + ['^mymethod$', '^wrong_.*$'] + today = datetime.date.today() def _load_code(expression): @@ -252,6 +256,18 @@ def test_constructor_types(data_filename, code_filename, verbose=False): test_constructor_types.unittest = ['.data', '.code'] +def test_subclass_blacklist_types(data_filename, verbose=False): + _make_objects() + try: + yaml.load(open(data_filename, 'rb').read(), MyFullLoader) + except yaml.YAMLError as exc: + if verbose: + print("%s:" % exc.__class__.__name__, exc) + else: + raise AssertionError("expected an exception") + +test_subclass_blacklist_types.unittest = ['.subclass_blacklist'] + if __name__ == '__main__': import sys, test_constructor sys.modules['test_constructor'] = sys.modules['__main__']
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor