Bug #97220 mysql-connector-python segfaults
Submitted: 14 Oct 2019 21:25 Modified: 19 Oct 2019 2:59
Reporter: A B Email Updates:
Status: Verified Impact on me:
None 
Category:Connector / Python Severity:S1 (Critical)
Version:8.0.18 OS:Ubuntu (18.04)
Assigned to: CPU Architecture:x86 (x86_64)

[14 Oct 2019 21:25] A B
Description:
mysql.connector.connect(**dbparams) crashes (segmentation fault) if the standard library module "random" is imported before mysql.connector.

Details:

The code inserted below (under "How to repeat") results in a segmentation fault.
If "import random" is commented out, then it works fine.

I am using Python 3.7.3 on Ubuntu 18.04, and a virtual environment with these modules installed:

> pip list
Package                Version
---------------------- -------
mysql-connector-python 8.0.18 
pip                    19.3   
protobuf               3.10.0 
setuptools             41.4.0 
six                    1.12.0 
wheel                  0.33.6

And I am connecting to the MySQL server that ships with Ubuntu
(5.7.27-0ubuntu0.18.04.1), in case this matters.

I hope you can fix this, and thanks for making mysql-connector-python
available!

Sincerely,
Anders Buch

How to repeat:
import random
import mysql.connector
dbparams = dict(host='localhost', user='asbuch', password='****')
mysql.connector.connect(**dbparams)
[16 Oct 2019 12:23] Umesh Shastry
Hello!

Thank you for the report and feedback.

regards,
Umesh
[17 Oct 2019 15:49] Johannes Schl├╝ter
Posted by developer:
 
Analysis:

The Python `random` module depends on `hash`, which depends on `_hash` which depends on `libyrypt.so`. Loading `random` will therefore load that system library from system path.

The Connector depends on `libssl.so`, which depends on `libcrypto.so` so when loading that the system's runtime linker will see "oh, libcrypto is already loaded, fine" unfortunately it loads our bundled libssl, which doesn't match the system libcrypto.

If the loading order in the script is changed to load random after the connector, the connector will load the bundled libssl, which loads the bundled libcrypto and the random module is happy.

If a user loads another module, which depends on libssl - say `urllib` - then that module will load the system's libssl and the system's libcrypto and the connector will be happy using those.

One might think that an easy fix would be to use the system's openssl and be fine, but that is no solution, since we want to have portable modules working on systems with older libraries. Since all of the loading is done by the runtime linker we only have limited control.

Work-arounds a use can do:

- reorder the `import` statements
- additionally load a module like `urllib`pulling in libssl and matching libcrypto
- enforcing to load libssl by setting `LD_PRELOAD=..../site-packages/mysql-vendor/libcrypto.so.1.1` in environment to force loading of that library and matching libcrypto on Python start

We need further research to find a solution.
[19 Oct 2019 2:59] A B
Thanks for the information.  However, the following code still results in a segmentation fault:

import urllib
import random
import mysql.connector
dbparams = dict(host='localhost', user='asbuch', password='****')
mysql.connector.connect(**dbparams)

The two other methods (reordering imports and setting LD_PRELOAD) work, but I would prefer to be able to import all standard library modules before vendor modules.  I think this is the recommended approach.

Anders