Skip to content

Commit 34637a0

Browse files
bpo-42103: Improve validation of Plist files. (GH-22882)
* 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.
1 parent 6fdfcec commit 34637a0

File tree

4 files changed

+363
-57
lines changed

4 files changed

+363
-57
lines changed

Lib/plistlib.py

+18-8
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ def parse(self, fp):
477477
return self._read_object(top_object)
478478

479479
except (OSError, IndexError, struct.error, OverflowError,
480-
UnicodeDecodeError):
480+
ValueError):
481481
raise InvalidFileException()
482482

483483
def _get_size(self, tokenL):
@@ -493,7 +493,7 @@ def _get_size(self, tokenL):
493493
def _read_ints(self, n, size):
494494
data = self._fp.read(size * n)
495495
if size in _BINARY_FORMAT:
496-
return struct.unpack('>' + _BINARY_FORMAT[size] * n, data)
496+
return struct.unpack(f'>{n}{_BINARY_FORMAT[size]}', data)
497497
else:
498498
if not size or len(data) != size * n:
499499
raise InvalidFileException()
@@ -553,14 +553,22 @@ def _read_object(self, ref):
553553
elif tokenH == 0x40: # data
554554
s = self._get_size(tokenL)
555555
result = self._fp.read(s)
556+
if len(result) != s:
557+
raise InvalidFileException()
556558

557559
elif tokenH == 0x50: # ascii string
558560
s = self._get_size(tokenL)
559-
result = self._fp.read(s).decode('ascii')
561+
data = self._fp.read(s)
562+
if len(data) != s:
563+
raise InvalidFileException()
564+
result = data.decode('ascii')
560565

561566
elif tokenH == 0x60: # unicode string
562-
s = self._get_size(tokenL)
563-
result = self._fp.read(s * 2).decode('utf-16be')
567+
s = self._get_size(tokenL) * 2
568+
data = self._fp.read(s)
569+
if len(data) != s:
570+
raise InvalidFileException()
571+
result = data.decode('utf-16be')
564572

565573
elif tokenH == 0x80: # UID
566574
# used by Key-Archiver plist files
@@ -585,9 +593,11 @@ def _read_object(self, ref):
585593
obj_refs = self._read_refs(s)
586594
result = self._dict_type()
587595
self._objects[ref] = result
588-
for k, o in zip(key_refs, obj_refs):
589-
result[self._read_object(k)] = self._read_object(o)
590-
596+
try:
597+
for k, o in zip(key_refs, obj_refs):
598+
result[self._read_object(k)] = self._read_object(o)
599+
except TypeError:
600+
raise InvalidFileException()
591601
else:
592602
raise InvalidFileException()
593603

0 commit comments

Comments
 (0)