Skip to content

Commit 547d2bc

Browse files
[3.8] bpo-42103: Improve validation of Plist files. (GH-22882) (GH-23116)
* Prevent some possible DoS attacks via providing invalid Plist files with extremely large number of objects or collection sizes. * Raise InvalidFileException for too large bytes and string size instead of returning garbage. * Raise InvalidFileException instead of ValueError for specific invalid datetime (NaN). * Raise InvalidFileException instead of TypeError for non-hashable dict keys. * Add more tests for invalid Plist files. (cherry picked from commit 34637a0)
1 parent 1e96de9 commit 547d2bc

File tree

4 files changed

+366
-61
lines changed

4 files changed

+366
-61
lines changed

Lib/plistlib.py

+21-12
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ def parse(self, fp):
600600
return self._read_object(top_object)
601601

602602
except (OSError, IndexError, struct.error, OverflowError,
603-
UnicodeDecodeError):
603+
ValueError):
604604
raise InvalidFileException()
605605

606606
def _get_size(self, tokenL):
@@ -616,7 +616,7 @@ def _get_size(self, tokenL):
616616
def _read_ints(self, n, size):
617617
data = self._fp.read(size * n)
618618
if size in _BINARY_FORMAT:
619-
return struct.unpack('>' + _BINARY_FORMAT[size] * n, data)
619+
return struct.unpack(f'>{n}{_BINARY_FORMAT[size]}', data)
620620
else:
621621
if not size or len(data) != size * n:
622622
raise InvalidFileException()
@@ -675,18 +675,25 @@ def _read_object(self, ref):
675675

676676
elif tokenH == 0x40: # data
677677
s = self._get_size(tokenL)
678-
if self._use_builtin_types:
679-
result = self._fp.read(s)
680-
else:
681-
result = Data(self._fp.read(s))
678+
result = self._fp.read(s)
679+
if len(result) != s:
680+
raise InvalidFileException()
681+
if not self._use_builtin_types:
682+
result = Data(result)
682683

683684
elif tokenH == 0x50: # ascii string
684685
s = self._get_size(tokenL)
685-
result = self._fp.read(s).decode('ascii')
686+
data = self._fp.read(s)
687+
if len(data) != s:
688+
raise InvalidFileException()
689+
result = data.decode('ascii')
686690

687691
elif tokenH == 0x60: # unicode string
688-
s = self._get_size(tokenL)
689-
result = self._fp.read(s * 2).decode('utf-16be')
692+
s = self._get_size(tokenL) * 2
693+
data = self._fp.read(s)
694+
if len(data) != s:
695+
raise InvalidFileException()
696+
result = data.decode('utf-16be')
690697

691698
elif tokenH == 0x80: # UID
692699
# used by Key-Archiver plist files
@@ -711,9 +718,11 @@ def _read_object(self, ref):
711718
obj_refs = self._read_refs(s)
712719
result = self._dict_type()
713720
self._objects[ref] = result
714-
for k, o in zip(key_refs, obj_refs):
715-
result[self._read_object(k)] = self._read_object(o)
716-
721+
try:
722+
for k, o in zip(key_refs, obj_refs):
723+
result[self._read_object(k)] = self._read_object(o)
724+
except TypeError:
725+
raise InvalidFileException()
717726
else:
718727
raise InvalidFileException()
719728

0 commit comments

Comments
 (0)