Skip to content

Commit a118c9a

Browse files
committed
Merge pull request #119 in SOLNSC/lib-solutions-python from bugfix/ADDON-26054-upgrade-pyyaml-to-5.3.1-or-later to master
* commit 'ae145f8419fd5e6b4bff83657a7f392d80e9b643': ADDON-26054:Updating the pyyaml version from 5.2 to 5.3.1 for security issue (ID: CVE-2020-1747)
2 parents 04bb39f + ae145f8 commit a118c9a

File tree

15 files changed

+126
-43
lines changed

15 files changed

+126
-43
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Splunk Solution Library for Python Changelog
22

3+
## Version 2.0.7
4+
* Updated `yaml` from 5.2 to 5.3.1 for security issue (ID: CVE-2020-1747) and fixed as part of ADDON-26054
5+
36
## Version 2.0.6
47
* Fixed server info `captain_info` method exception handling python2/3 compatibility issue
58

solnlib/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,4 @@
6060
'user_access',
6161
'utils']
6262

63-
__version__ = '2.0.6'
63+
__version__ = '2.0.7'

solnlib/packages/yamlpy2/LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (c) 2017-2019 Ingy döt Net
1+
Copyright (c) 2017-2020 Ingy döt Net
22
Copyright (c) 2006-2016 Kirill Simonov
33

44
Permission is hereby granted, free of charge, to any person obtaining a copy of

solnlib/packages/yamlpy2/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from loader import *
99
from dumper import *
1010

11-
__version__ = '5.2'
11+
__version__ = '5.3.1'
1212

1313
try:
1414
from cyaml import *
@@ -345,7 +345,7 @@ def add_constructor(tag, constructor, Loader=None):
345345
Constructor is a function that accepts a Loader instance
346346
and a node object and produces the corresponding Python object.
347347
"""
348-
if Loader == None:
348+
if Loader is None:
349349
loader.Loader.add_constructor(tag, constructor)
350350
loader.FullLoader.add_constructor(tag, constructor)
351351
loader.UnsafeLoader.add_constructor(tag, constructor)
@@ -359,7 +359,7 @@ def add_multi_constructor(tag_prefix, multi_constructor, Loader=None):
359359
Multi-constructor accepts a Loader instance, a tag suffix,
360360
and a node object and produces the corresponding Python object.
361361
"""
362-
if Loader == None:
362+
if Loader is None:
363363
loader.Loader.add_multi_constructor(tag_prefix, multi_constructor)
364364
loader.FullLoader.add_multi_constructor(tag_prefix, multi_constructor)
365365
loader.UnsafeLoader.add_multi_constructor(tag_prefix, multi_constructor)

solnlib/packages/yamlpy2/constructor.py

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,29 @@
1818
class ConstructorError(MarkedYAMLError):
1919
pass
2020

21+
22+
class timezone(datetime.tzinfo):
23+
def __init__(self, offset):
24+
self._offset = offset
25+
seconds = abs(offset).total_seconds()
26+
self._name = 'UTC%s%02d:%02d' % (
27+
'-' if offset.days < 0 else '+',
28+
seconds // 3600,
29+
seconds % 3600 // 60
30+
)
31+
32+
def tzname(self, dt=None):
33+
return self._name
34+
35+
def utcoffset(self, dt=None):
36+
return self._offset
37+
38+
def dst(self, dt=None):
39+
return datetime.timedelta(0)
40+
41+
__repr__ = __str__ = tzname
42+
43+
2144
class BaseConstructor(object):
2245

2346
yaml_constructors = {}
@@ -33,6 +56,14 @@ def check_data(self):
3356
# If there are more documents available?
3457
return self.check_node()
3558

59+
def check_state_key(self, key):
60+
"""Block special attributes/methods from being set in a newly created
61+
object, to prevent user-controlled methods from being called during
62+
deserialization"""
63+
if self.get_state_keys_blacklist_regexp().match(key):
64+
raise ConstructorError(None, None,
65+
"blacklisted key '%s' in instance state found" % (key,), None)
66+
3667
def get_data(self):
3768
# Construct and return the next document.
3869
if self.check_node():
@@ -74,7 +105,7 @@ def construct_object(self, node, deep=False):
74105
constructor = self.yaml_constructors[node.tag]
75106
else:
76107
for tag_prefix in self.yaml_multi_constructors:
77-
if node.tag.startswith(tag_prefix):
108+
if tag_prefix is not None and node.tag.startswith(tag_prefix):
78109
tag_suffix = node.tag[len(tag_prefix):]
79110
constructor = self.yaml_multi_constructors[tag_prefix]
80111
break
@@ -293,7 +324,7 @@ def construct_yaml_binary(self, node):
293324
return str(value).decode('base64')
294325
except (binascii.Error, UnicodeEncodeError), exc:
295326
raise ConstructorError(None, None,
296-
"failed to decode base64 data: %s" % exc, node.start_mark)
327+
"failed to decode base64 data: %s" % exc, node.start_mark)
297328

298329
timestamp_regexp = re.compile(
299330
ur'''^(?P<year>[0-9][0-9][0-9][0-9])
@@ -320,22 +351,23 @@ def construct_yaml_timestamp(self, node):
320351
minute = int(values['minute'])
321352
second = int(values['second'])
322353
fraction = 0
354+
tzinfo = None
323355
if values['fraction']:
324356
fraction = values['fraction'][:6]
325357
while len(fraction) < 6:
326358
fraction += '0'
327359
fraction = int(fraction)
328-
delta = None
329360
if values['tz_sign']:
330361
tz_hour = int(values['tz_hour'])
331362
tz_minute = int(values['tz_minute'] or 0)
332363
delta = datetime.timedelta(hours=tz_hour, minutes=tz_minute)
333364
if values['tz_sign'] == '-':
334365
delta = -delta
335-
data = datetime.datetime(year, month, day, hour, minute, second, fraction)
336-
if delta:
337-
data -= delta
338-
return data
366+
tzinfo = timezone(delta)
367+
elif values['tz']:
368+
tzinfo = timezone(datetime.timedelta(0))
369+
return datetime.datetime(year, month, day, hour, minute, second, fraction,
370+
tzinfo=tzinfo)
339371

340372
def construct_yaml_omap(self, node):
341373
# Note: we do not check for duplicate keys, because it's too
@@ -471,6 +503,16 @@ def construct_undefined(self, node):
471503
SafeConstructor.construct_undefined)
472504

473505
class FullConstructor(SafeConstructor):
506+
# 'extend' is blacklisted because it is used by
507+
# construct_python_object_apply to add `listitems` to a newly generate
508+
# python instance
509+
def get_state_keys_blacklist(self):
510+
return ['^extend$', '^__.*__$']
511+
512+
def get_state_keys_blacklist_regexp(self):
513+
if not hasattr(self, 'state_keys_blacklist_regexp'):
514+
self.state_keys_blacklist_regexp = re.compile('(' + '|'.join(self.get_state_keys_blacklist()) + ')')
515+
return self.state_keys_blacklist_regexp
474516

475517
def construct_python_str(self, node):
476518
return self.construct_scalar(node).encode('utf-8')
@@ -497,7 +539,7 @@ def find_python_module(self, name, mark, unsafe=False):
497539
except ImportError, exc:
498540
raise ConstructorError("while constructing a Python module", mark,
499541
"cannot find module %r (%s)" % (name.encode('utf-8'), exc), mark)
500-
if not name in sys.modules:
542+
if name not in sys.modules:
501543
raise ConstructorError("while constructing a Python module", mark,
502544
"module %r is not imported" % name.encode('utf-8'), mark)
503545
return sys.modules[name]
@@ -517,7 +559,7 @@ def find_python_name(self, name, mark, unsafe=False):
517559
except ImportError, exc:
518560
raise ConstructorError("while constructing a Python object", mark,
519561
"cannot find module %r (%s)" % (module_name.encode('utf-8'), exc), mark)
520-
if not module_name in sys.modules:
562+
if module_name not in sys.modules:
521563
raise ConstructorError("while constructing a Python object", mark,
522564
"module %r is not imported" % module_name.encode('utf-8'), mark)
523565
module = sys.modules[module_name]
@@ -566,19 +608,24 @@ def make_python_instance(self, suffix, node,
566608
else:
567609
return cls(*args, **kwds)
568610

569-
def set_python_instance_state(self, instance, state):
611+
def set_python_instance_state(self, instance, state, unsafe=False):
570612
if hasattr(instance, '__setstate__'):
571613
instance.__setstate__(state)
572614
else:
573615
slotstate = {}
574616
if isinstance(state, tuple) and len(state) == 2:
575617
state, slotstate = state
576618
if hasattr(instance, '__dict__'):
619+
if not unsafe and state:
620+
for key in state.keys():
621+
self.check_state_key(key)
577622
instance.__dict__.update(state)
578623
elif state:
579624
slotstate.update(state)
580625
for key, value in slotstate.items():
581-
setattr(object, key, value)
626+
if not unsafe:
627+
self.check_state_key(key)
628+
setattr(instance, key, value)
582629

583630
def construct_python_object(self, suffix, node):
584631
# Format:
@@ -699,6 +746,10 @@ def make_python_instance(self, suffix, node, args=None, kwds=None, newobj=False)
699746
return super(UnsafeConstructor, self).make_python_instance(
700747
suffix, node, args, kwds, newobj, unsafe=True)
701748

749+
def set_python_instance_state(self, instance, state):
750+
return super(UnsafeConstructor, self).set_python_instance_state(
751+
instance, state, unsafe=True)
752+
702753
UnsafeConstructor.add_multi_constructor(
703754
u'tag:yaml.org,2002:python/object/apply:',
704755
UnsafeConstructor.construct_python_object_apply)

solnlib/packages/yamlpy2/loader.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def __init__(self, stream):
5151
# UnsafeLoader is the same as Loader (which is and was always unsafe on
5252
# untrusted input). Use of either Loader or UnsafeLoader should be rare, since
5353
# FullLoad should be able to load almost all YAML safely. Loader is left intact
54-
# to ensure backwards compatability.
54+
# to ensure backwards compatibility.
5555
class UnsafeLoader(Reader, Scanner, Parser, Composer, Constructor, Resolver):
5656

5757
def __init__(self, stream):

solnlib/packages/yamlpy2/reader.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ def determine_encoding(self):
139139
if has_ucs4:
140140
NON_PRINTABLE = re.compile(u'[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD\U00010000-\U0010ffff]')
141141
else:
142-
NON_PRINTABLE = re.compile(u'[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD]')
142+
NON_PRINTABLE = re.compile(u'[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uFFFD]|(?:^|[^\uD800-\uDBFF])[\uDC00-\uDFFF]|[\uD800-\uDBFF](?:[^\uDC00-\uDFFF]|$)')
143143
def check_printable(self, data):
144144
match = self.NON_PRINTABLE.search(data)
145145
if match:

solnlib/packages/yamlpy2/representer.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
'RepresenterError']
44

55
from error import *
6+
67
from nodes import *
78

89
import datetime
910

10-
import sys, copy_reg, types
11+
import copy_reg, types
1112

1213
class RepresenterError(YAMLError):
1314
pass

solnlib/packages/yamlpy2/scanner.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ def unwind_indent(self, column):
332332
## }
333333
#if self.flow_level and self.indent > column:
334334
# raise ScannerError(None, None,
335-
# "invalid intendation or unclosed '[' or '{'",
335+
# "invalid indentation or unclosed '[' or '{'",
336336
# self.get_mark())
337337

338338
# In the flow context, indentation is ignored. We make the scanner less
@@ -370,7 +370,7 @@ def fetch_stream_start(self):
370370

371371
def fetch_stream_end(self):
372372

373-
# Set the current intendation to -1.
373+
# Set the current indentation to -1.
374374
self.unwind_indent(-1)
375375

376376
# Reset simple keys.
@@ -389,7 +389,7 @@ def fetch_stream_end(self):
389389

390390
def fetch_directive(self):
391391

392-
# Set the current intendation to -1.
392+
# Set the current indentation to -1.
393393
self.unwind_indent(-1)
394394

395395
# Reset simple keys.
@@ -407,7 +407,7 @@ def fetch_document_end(self):
407407

408408
def fetch_document_indicator(self, TokenClass):
409409

410-
# Set the current intendation to -1.
410+
# Set the current indentation to -1.
411411
self.unwind_indent(-1)
412412

413413
# Reset simple keys. Note that there could not be a block collection

solnlib/packages/yamlpy3/LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (c) 2017-2019 Ingy döt Net
1+
Copyright (c) 2017-2020 Ingy döt Net
22
Copyright (c) 2006-2016 Kirill Simonov
33

44
Permission is hereby granted, free of charge, to any person obtaining a copy of

0 commit comments

Comments
 (0)