classification
Title: Crash when throwing an exception with a malicious __hash__ override
Type: Stage: resolved
Components: Interpreter Core Versions: Python 3.7, Python 3.6
process
Status: closed Resolution: out of date
Dependencies: 25782 Superseder: traceback module can't format/print unhashable exceptions
View: 28603
Assigned To: Nosy List: Jelle Zijlstra, josh.r, serhiy.storchaka, xcombelle
Priority: normal Keywords:

Created on 2016-12-13 16:28 by Jelle Zijlstra, last changed 2018-06-03 09:59 by serhiy.storchaka. This issue is now closed.

Files
File name Uploaded Description Edit
baderror.py Jelle Zijlstra, 2016-12-13 16:28
Messages (5)
msg283118 - (view) Author: Jelle Zijlstra (Jelle Zijlstra) * (Python triager) Date: 2016-12-13 16:28
$ cat baderror.py 
class BadError(Exception):
    def __init__(self):
        self.i = 0

    def __hash__(self):
        self.i += 1
        return self.i


e = BadError()
raise e from e
$ ./python.exe -V
Python 3.5.2+
$ ./python.exe baderror.py 
Segmentation fault: 11

I have reproduced this with Python 3.3, 3.4, 3.5, and 3.6; I assume it's been present throughout the 3 series.

This is because print_exception_recursive in pythonrun.c keeps following the __cause__ chain, and here the exception is its own __cause__. It uses a set to ensure that it breaks cycles, but that doesn't help here because of the exception's incorrect __hash__ method.
msg283139 - (view) Author: Josh Rosenberg (josh.r) * (Python triager) Date: 2016-12-13 20:15
Is this something that needs to be defended against? My understanding is that it's pretty easy to segfault CPython in a number of ways if you can execute 100% arbitrary code. The only way to cause this problem is if you can define malicious exceptions and cause one to be raised from itself, neither of which occurs in reasonable code.
msg283831 - (view) Author: Xavier Combelle (xcombelle) * Date: 2016-12-22 13:16
To my knowledge it is not the kind of arbitrary code which could segfault python code. It is far different for example that the fact by using bytecode magic you can segfault the interpreter, as this last case is explicitly warned in documentation.
msg314241 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-03-22 09:58
Seems it was fixed somewhere between 3.6.3 and 3.6.5+.

Traceback (most recent call last):
  File "baderror.py", line 10, in <module>
    raise e from e
__main__.BadError

3.5 is now in security-only fixes stage, and this doesn't look like a security issue.
msg318531 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-06-03 09:59
It was fixed in issue28603.
History
Date User Action Args
2018-06-03 09:59:49serhiy.storchakasetstatus: open -> closed
resolution: out of date
messages: + msg318531

stage: resolved
2018-06-03 09:36:43serhiy.storchakasetsuperseder: traceback module can't format/print unhashable exceptions
2018-03-22 09:58:11serhiy.storchakasetversions: - Python 3.3
2018-03-22 09:58:00serhiy.storchakasetnosy: + serhiy.storchaka

messages: + msg314241
versions: - Python 3.4, Python 3.5
2016-12-22 13:16:49xcombellesetnosy: + xcombelle
messages: + msg283831
2016-12-13 20:47:06serhiy.storchakasetdependencies: + CPython hangs on error __context__ set to the error itself
2016-12-13 20:15:24josh.rsetnosy: + josh.r
messages: + msg283139
2016-12-13 16:28:07Jelle Zijlstracreate