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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy