c4c736c2d0bb13564903ceb33dcbb64c07b14d87
[openwrt-packages.git] /
1 From f56c75ed53dcad4d59dff4377ae463d6b96acd3e Mon Sep 17 00:00:00 2001
2 From: "Miss Islington (bot)"
3  <31488909+miss-islington@users.noreply.github.com>
4 Date: Mon, 13 Jul 2020 06:05:44 -0700
5 Subject: [PATCH] bpo-41288: Fix a crash in unpickling invalid NEWOBJ_EX.
6  (GH-21458)
7
8 Automerge-Triggered-By: @tiran
9 (cherry picked from commit 4f309abf55f0e6f8950ac13d6ec83c22b8d47bf8)
10
11 Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
12 ---
13  Lib/test/pickletester.py                      | 18 ++++++++++++
14  .../2020-07-13-15-06-35.bpo-41288.8mn5P-.rst  |  2 ++
15  Modules/_pickle.c                             | 29 ++++++++++++++-----
16  3 files changed, 41 insertions(+), 8 deletions(-)
17  create mode 100644 Misc/NEWS.d/next/Library/2020-07-13-15-06-35.bpo-41288.8mn5P-.rst
18
19 diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py
20 index 9401043d78d18..ff7bbb0c8a9bf 100644
21 --- a/Lib/test/pickletester.py
22 +++ b/Lib/test/pickletester.py
23 @@ -1170,6 +1170,24 @@ def test_compat_unpickle(self):
24              self.assertIs(type(unpickled), collections.UserDict)
25              self.assertEqual(unpickled, collections.UserDict({1: 2}))
26  
27 +    def test_bad_reduce(self):
28 +        self.assertEqual(self.loads(b'cbuiltins\nint\n)R.'), 0)
29 +        self.check_unpickling_error(TypeError, b'N)R.')
30 +        self.check_unpickling_error(TypeError, b'cbuiltins\nint\nNR.')
31 +
32 +    def test_bad_newobj(self):
33 +        error = (pickle.UnpicklingError, TypeError)
34 +        self.assertEqual(self.loads(b'cbuiltins\nint\n)\x81.'), 0)
35 +        self.check_unpickling_error(error, b'cbuiltins\nlen\n)\x81.')
36 +        self.check_unpickling_error(error, b'cbuiltins\nint\nN\x81.')
37 +
38 +    def test_bad_newobj_ex(self):
39 +        error = (pickle.UnpicklingError, TypeError)
40 +        self.assertEqual(self.loads(b'cbuiltins\nint\n)}\x92.'), 0)
41 +        self.check_unpickling_error(error, b'cbuiltins\nlen\n)}\x92.')
42 +        self.check_unpickling_error(error, b'cbuiltins\nint\nN}\x92.')
43 +        self.check_unpickling_error(error, b'cbuiltins\nint\n)N\x92.')
44 +
45      def test_bad_stack(self):
46          badpickles = [
47              b'.',                       # STOP
48 diff --git a/Misc/NEWS.d/next/Library/2020-07-13-15-06-35.bpo-41288.8mn5P-.rst b/Misc/NEWS.d/next/Library/2020-07-13-15-06-35.bpo-41288.8mn5P-.rst
49 new file mode 100644
50 index 0000000000000..3c3adbabf16ff
51 --- /dev/null
52 +++ b/Misc/NEWS.d/next/Library/2020-07-13-15-06-35.bpo-41288.8mn5P-.rst
53 @@ -0,0 +1,2 @@
54 +Unpickling invalid NEWOBJ_EX opcode with the C implementation raises now
55 +UnpicklingError instead of crashing.
56 diff --git a/Modules/_pickle.c b/Modules/_pickle.c
57 index 55affb2c7c479..42ce62fc7cdf4 100644
58 --- a/Modules/_pickle.c
59 +++ b/Modules/_pickle.c
60 @@ -5988,23 +5988,30 @@ load_newobj_ex(UnpicklerObject *self)
61      }
62  
63      if (!PyType_Check(cls)) {
64 -        Py_DECREF(kwargs);
65 -        Py_DECREF(args);
66          PyErr_Format(st->UnpicklingError,
67                       "NEWOBJ_EX class argument must be a type, not %.200s",
68                       Py_TYPE(cls)->tp_name);
69 -        Py_DECREF(cls);
70 -        return -1;
71 +        goto error;
72      }
73  
74      if (((PyTypeObject *)cls)->tp_new == NULL) {
75 -        Py_DECREF(kwargs);
76 -        Py_DECREF(args);
77 -        Py_DECREF(cls);
78          PyErr_SetString(st->UnpicklingError,
79                          "NEWOBJ_EX class argument doesn't have __new__");
80 -        return -1;
81 +        goto error;
82 +    }
83 +    if (!PyTuple_Check(args)) {
84 +        PyErr_Format(st->UnpicklingError,
85 +                     "NEWOBJ_EX args argument must be a tuple, not %.200s",
86 +                     Py_TYPE(args)->tp_name);
87 +        goto error;
88 +    }
89 +    if (!PyDict_Check(kwargs)) {
90 +        PyErr_Format(st->UnpicklingError,
91 +                     "NEWOBJ_EX kwargs argument must be a dict, not %.200s",
92 +                     Py_TYPE(kwargs)->tp_name);
93 +        goto error;
94      }
95 +
96      obj = ((PyTypeObject *)cls)->tp_new((PyTypeObject *)cls, args, kwargs);
97      Py_DECREF(kwargs);
98      Py_DECREF(args);
99 @@ -6014,6 +6021,12 @@ load_newobj_ex(UnpicklerObject *self)
100      }
101      PDATA_PUSH(self->stack, obj, -1);
102      return 0;
103 +
104 +error:
105 +    Py_DECREF(kwargs);
106 +    Py_DECREF(args);
107 +    Py_DECREF(cls);
108 +    return -1;
109  }
110  
111  static int
git clone https://git.99rst.org/PROJECT