From b272ff74ae319a82e4d3e3de1348b2a6115f6501 Mon Sep 17 00:00:00 2001 From: Paul Ivanov Date: Wed, 30 Jan 2019 14:22:44 -0800 Subject: [PATCH] BUG: load fails when using pickle without allow_pickle=True a partial mitigation of #12759. see also https://nvd.nist.gov/vuln/detail/CVE-2019-6446 --- numpy/core/tests/test_regression.py | 2 +- numpy/lib/format.py | 8 ++++++-- numpy/lib/npyio.py | 17 ++++++++++++----- numpy/lib/tests/test_format.py | 15 +++++++++------ numpy/lib/tests/test_io.py | 2 +- 5 files changed, 29 insertions(+), 15 deletions(-) diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py index 52793d453..b144aec17 100644 --- a/numpy/core/tests/test_regression.py +++ b/numpy/core/tests/test_regression.py @@ -96,7 +96,7 @@ class TestRegression(object): ca = np.char.array(np.arange(1000, 1010), itemsize=4) ca.dump(f) f.seek(0) - ca = np.load(f) + ca = np.load(f, allow_pickle=True) f.close() def test_noncontiguous_fill(self): diff --git a/numpy/lib/format.py b/numpy/lib/format.py index 363bb2101..e6144b3a6 100644 --- a/numpy/lib/format.py +++ b/numpy/lib/format.py @@ -602,7 +602,7 @@ def write_array(fp, array, version=None, allow_pickle=True, pickle_kwargs=None): fp.write(chunk.tobytes('C')) -def read_array(fp, allow_pickle=True, pickle_kwargs=None): +def read_array(fp, allow_pickle=False, pickle_kwargs=None): """ Read an array from an NPY file. @@ -612,7 +612,11 @@ def read_array(fp, allow_pickle=True, pickle_kwargs=None): If this is not a real file object, then this may take extra memory and time. allow_pickle : bool, optional - Whether to allow reading pickled data. Default: True + Whether to allow writing pickled data. Default: False + + .. versionchanged:: 1.14.3 + Made default False in response to CVE-2019-6446. + pickle_kwargs : dict Additional keyword arguments to pass to pickle.load. These are only useful when loading object arrays saved on Python 2 when using diff --git a/numpy/lib/npyio.py b/numpy/lib/npyio.py index 76b135cc2..ef84d68fd 100644 --- a/numpy/lib/npyio.py +++ b/numpy/lib/npyio.py @@ -130,7 +130,11 @@ class NpzFile(object): An object on which attribute can be performed as an alternative to getitem access on the `NpzFile` instance itself. allow_pickle : bool, optional - Allow loading pickled data. Default: True + Allow loading pickled data. Default: False + + .. versionchanged:: 1.14.3 + Made default False in response to CVE-2019-6446. + pickle_kwargs : dict, optional Additional keyword arguments to pass on to pickle.load. These are only useful when loading object arrays saved on @@ -166,7 +170,7 @@ class NpzFile(object): """ - def __init__(self, fid, own_fid=False, allow_pickle=True, + def __init__(self, fid, own_fid=False, allow_pickle=False, pickle_kwargs=None): # Import is postponed to here since zipfile depends on gzip, an # optional component of the so-called standard library. @@ -265,7 +269,7 @@ class NpzFile(object): return self.files.__contains__(key) -def load(file, mmap_mode=None, allow_pickle=True, fix_imports=True, +def load(file, mmap_mode=None, allow_pickle=False, fix_imports=True, encoding='ASCII'): """ Load arrays or pickled objects from ``.npy``, ``.npz`` or pickled files. @@ -287,8 +291,11 @@ def load(file, mmap_mode=None, allow_pickle=True, fix_imports=True, Allow loading pickled object arrays stored in npy files. Reasons for disallowing pickles include security, as loading pickled data can execute arbitrary code. If pickles are disallowed, loading object - arrays will fail. - Default: True + arrays will fail. Default: False + + .. versionchanged:: 1.14.3 + Made default False in response to CVE-2019-6446. + fix_imports : bool, optional Only useful when loading Python 2 generated pickled files on Python 3, which includes npy/npz files containing object arrays. If `fix_imports` diff --git a/numpy/lib/tests/test_format.py b/numpy/lib/tests/test_format.py index 2d2b4cea2..04e090ca7 100644 --- a/numpy/lib/tests/test_format.py +++ b/numpy/lib/tests/test_format.py @@ -426,7 +426,7 @@ def roundtrip(arr): f = BytesIO() format.write_array(f, arr) f2 = BytesIO(f.getvalue()) - arr2 = format.read_array(f2) + arr2 = format.read_array(f2, allow_pickle=True) return arr2 @@ -553,7 +553,7 @@ def test_pickle_python2_python3(): path = os.path.join(data_dir, fname) for encoding in ['bytes', 'latin1']: - data_f = np.load(path, encoding=encoding) + data_f = np.load(path, allow_pickle=True, encoding=encoding) if fname.endswith('.npz'): data = data_f['x'] data_f.close() @@ -575,16 +575,19 @@ def test_pickle_python2_python3(): if sys.version_info[0] >= 3: if fname.startswith('py2'): if fname.endswith('.npz'): - data = np.load(path) + data = np.load(path, allow_pickle=True) assert_raises(UnicodeError, data.__getitem__, 'x') data.close() - data = np.load(path, fix_imports=False, encoding='latin1') + data = np.load(path, allow_pickle=True, fix_imports=False, + encoding='latin1') assert_raises(ImportError, data.__getitem__, 'x') data.close() else: - assert_raises(UnicodeError, np.load, path) + assert_raises(UnicodeError, np.load, path, + allow_pickle=True) assert_raises(ImportError, np.load, path, - encoding='latin1', fix_imports=False) + allow_pickle=True, fix_imports=False, + encoding='latin1') def test_pickle_disallow(): diff --git a/numpy/lib/tests/test_io.py b/numpy/lib/tests/test_io.py index 2daa0153b..bde256741 100644 --- a/numpy/lib/tests/test_io.py +++ b/numpy/lib/tests/test_io.py @@ -87,7 +87,7 @@ class RoundtripTest(object): """ save_kwds = kwargs.get('save_kwds', {}) - load_kwds = kwargs.get('load_kwds', {}) + load_kwds = kwargs.get('load_kwds', {"allow_pickle": True}) file_on_disk = kwargs.get('file_on_disk', False) if file_on_disk: -- 2.21.0