From a7d0dbf5ecebcbe73a7514de9b61c8312df5f647 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Fri, 12 Aug 2022 01:20:58 -0700 Subject: [PATCH 1/3] Drop the safety claim from ast.literal_eval docs. It was never safe and this claim conflicts directly with the big warning in the docs about it being able to crash the interpreter. --- Doc/library/ast.rst | 23 ++++++++++++------- Lib/ast.py | 4 +++- ...2-08-12-01-12-52.gh-issue-95588.PA0FI7.rst | 6 +++++ 3 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index 9aa545d82007fa..b0020d64f17e7e 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -1991,20 +1991,27 @@ and classes for traversing abstract syntax trees: .. function:: literal_eval(node_or_string) - Safely evaluate an expression node or a string containing a Python literal or + Evaluate an expression node or a string containing a Python literal or container display. The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, ``None`` and ``Ellipsis``. - This can be used for safely evaluating strings containing Python values from - untrusted sources without the need to parse the values oneself. It is not - capable of evaluating arbitrarily complex expressions, for example involving - operators or indexing. + This can be used for evaluating strings containing Python values without the + need to parse the values oneself. It is not capable of evaluating + arbitrarily complex expressions, for example involving operators or + indexing. + + This function had been documented as "safe" in the past without defining + what that meant. That was misleading. This is specifically designed not to + execute Python code, unlike the more general :func:`eval`. There is no + namespace, no name lookups, or ability to call out. But it is not free from + attack: A relatively small input can lead to memory exhaustion or to C stack + exhaustion, crashing the process. Calling it on untrusted input is thus + unwise. .. warning:: - It is possible to crash the Python interpreter with a - sufficiently large/complex string due to stack depth limitations - in Python's AST compiler. + It is possible to crash the Python interpreter with a complex string due + to stack depth limitations in Python's AST compiler. It can raise :exc:`ValueError`, :exc:`TypeError`, :exc:`SyntaxError`, :exc:`MemoryError` and :exc:`RecursionError` depending on the malformed diff --git a/Lib/ast.py b/Lib/ast.py index ebf4529f79b060..311c1d7fc95d32 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -54,10 +54,12 @@ def parse(source, filename='', mode='exec', *, def literal_eval(node_or_string): """ - Safely evaluate an expression node or a string containing a Python + Evaluate an expression node or a string containing only a Python expression. The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None. + + Caution: A complex expression can overflow the C stack and cause a crash. """ if isinstance(node_or_string, str): node_or_string = parse(node_or_string.lstrip(" \t"), mode='eval') diff --git a/Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst b/Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst new file mode 100644 index 00000000000000..c070bbc19517fc --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2022-08-12-01-12-52.gh-issue-95588.PA0FI7.rst @@ -0,0 +1,6 @@ +Clarified the conflicting advice given in the :mod:`ast` documentation about +:func:`ast.literal_eval` being "safe" for use on untrusted input while at +the same time warning that it can crash the process. The latter statement is +true and is deemed unfixable without a large amount of work unsuitable for a +bugfix. So we keep the warning and no longer claim that ``literal_eval`` is +safe. From d2632af1714cf30a6f6f8c62358681927113fe48 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Fri, 12 Aug 2022 01:35:21 -0700 Subject: [PATCH 2/3] add the word only as I did in the docstring. --- Doc/library/ast.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index b0020d64f17e7e..4a4b11f6f0cdaa 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -1991,7 +1991,7 @@ and classes for traversing abstract syntax trees: .. function:: literal_eval(node_or_string) - Evaluate an expression node or a string containing a Python literal or + Evaluate an expression node or a string containing only a Python literal or container display. The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, ``None`` and ``Ellipsis``. From f01289c582c0361ebe30ac4e10ad3a611df9ab85 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith [Google]" Date: Sat, 1 Oct 2022 18:40:25 +0000 Subject: [PATCH 3/3] Adjust wording per vstinner's review. --- Doc/library/ast.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Doc/library/ast.rst b/Doc/library/ast.rst index 8f45a65eebb1e2..0811b3fa0e7842 100644 --- a/Doc/library/ast.rst +++ b/Doc/library/ast.rst @@ -2006,12 +2006,13 @@ and classes for traversing abstract syntax trees: execute Python code, unlike the more general :func:`eval`. There is no namespace, no name lookups, or ability to call out. But it is not free from attack: A relatively small input can lead to memory exhaustion or to C stack - exhaustion, crashing the process. Calling it on untrusted input is thus - unwise. + exhaustion, crashing the process. There is also the possibility for + excessive CPU consumption denial of service on some inputs. Calling it on + untrusted data is thus not recommended. .. warning:: - It is possible to crash the Python interpreter with a complex string due - to stack depth limitations in Python's AST compiler. + It is possible to crash the Python interpreter due to stack depth + limitations in Python's AST compiler. It can raise :exc:`ValueError`, :exc:`TypeError`, :exc:`SyntaxError`, :exc:`MemoryError` and :exc:`RecursionError` depending on the malformed