8000 [3.6] bpo-42103: Improve validation of Plist files. (GH-22882) (GH-23… · python/cpython@a63234c · GitHub
[go: up one dir, main page]

Skip to content

Commit a63234c

Browse files
[3.6] bpo-42103: Improve validation of Plist files. (GH-22882) (GH-23118)
* 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) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent a75c4c9 commit a63234c

File tree

4 files changed

+367
-67
lines changed

4 files changed

+367
-67
lines changed

Lib/plistlib.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ def parse(self, fp):
633633
return self._read_object(top_object)
634634

635635
except (OSError, IndexError, struct.error, OverflowError,
636-
UnicodeDecodeError):
636+
ValueError):
637637
raise InvalidFileException()
638638

639639
def _get_size(self, tokenL):
@@ -649,7 +649,7 @@ def _get_size(self, tokenL):
649649
def _read_ints(self, n, size):
650650
data = self._fp.read(size * n)
651651
if size in _BINARY_FORMAT:
652-
return struct.unpack('>' + _BINARY_FORMAT[size] * n, data)
652+
return struct.unpack(f'>{n}{_BINARY_FORMAT[size]}', data)
653653
else:
654654
if not size or len(data) != size * n:
655655
raise InvalidFileException()
@@ -708,19 +708,25 @@ def _read_object(self, ref):
708708

709709
elif tokenH == 0x40: # data
710710
s = self._get_size(tokenL)
711-
if self._use_builtin_types:
712-
result = self._fp.read(s)
713-
else:
714-
result = Data(self._fp.read(s))
711+
result = self._fp.read(s)
712+
if len(result) != s:
713+
raise InvalidFileException()
714+
if not self._use_builtin_types:
715+
result = Data(result)
715716

716717
elif tokenH == 0x50: # ascii string
717718
s = self._get_size(tokenL)
718-
result = self._fp.read(s).decode('ascii')
719-
result = result
719+
data = self._fp.read(s)
720+
if len(data) != s:
721+
raise InvalidFileException()
722+
result = data.decode('ascii')
720723

721724
elif tokenH == 0x60: # unicode string
722-
s = self._get_size(tokenL)
723-
result = self._fp.read(s * 2).decode('utf-16be')
725+
s = self._get_size(tokenL) * 2
726+
data = self._fp.read(s)
727+
if len(data) != s:
728+
raise InvalidFileException()
729+
result = data.decode('utf-16be')
724730

725731
# tokenH == 0x80 is documented as 'UID' and appears to be used for
726732
# keyed-archiving, not in plists.
@@ -744,9 +750,11 @@ def _read_object(self, ref):
744750
obj_refs = self._read_refs(s)
745751
result = self._dict_type()
746752
self._objects[ref] = result
747-
for k, o in zip(key_refs, obj_refs):
748-
result[self._read_object(k)] = self._read_object(o)
749-
753+
try:
754+
for k, o in zip(key_refs, obj_refs):
755+
result[self._read_object(k)] = self._read_object(o)
756+
except TypeError:
757+
raise InvalidFileException()
750758
else:
751759
raise InvalidFileException()
752760

0 commit comments

Comments
 (0)
0