【问题标题】:Coredump when compiling python with a custom openssl version使用自定义 openssl 版本编译 python 时的 Coredump
【发布时间】:2014-04-19 23:39:37
【问题描述】:

当使用本地 openssl-1.0.1f 共享安装编译 python-3.4.0rc3 时,make 没有打印错误,但随后我在 make install 或 make test 上得到以下核心转储:

Program terminated with signal 11, Segmentation fault.
(gdb) bt
#0  0x00007f131dd10510 in EVP_PKEY_CTX_dup () from /data2/soft/openssl/lib/libcrypto.so.1.0.0
#1  0x00007f131dd0284f in EVP_MD_CTX_copy_ex () from /data2/soft/openssl/lib/libcrypto.so.1.0.0
#2  0x00007f131e256ab5 in EVPnew (name_obj=0x7f131e46a500, digest=0x0, initial_ctx=0x7f131e459a40, cp=0x0, len=0) at /data2/soft/python3/Python-3.4.0rc3/Modules/_hashopenssl.c:410
#3  0x00007f131e25726e in EVP_new_md5 (self=<value optimized out>, args=<value optimized out>) at /data2/soft/python3/Python-3.4.0rc3/Modules/_hashopenssl.c:799
#4  0x00000000004c7eef in ?? ()

这里是使用的命令的完整列表

tar -axf Python-3.4.0rc3.tgz
cd Python-3*
# For lzma and a pip-compatible openssl
export CFLAGS='-I/data2/soft/openssl/include/openssl -I/data2/local/include/'
export LDFLAGS='-L/data2/soft/openssl/lib -L/data2/local/lib/'
export LD_LIBRARY_PATH="/data2/soft/openssl/lib:/data2/local/lib/:$LD_LIBRARY_PATH"
# Ready !
./configure --prefix=/data2/soft/python3
make
make install

注意事项:

  • 操作系统是 SUSE Linux Enterprise Server 11 (x86_64)
  • 将 python 指向 lzma 库的自定义位置
  • openssl 是用./config shared --openssldir=/data2/soft/openssl 构建的
  • openssl make test 打印 所有测试都成功。
  • 没有自定义 openssl *FLAGS,make install 成功,我得到了 make test 的这些结果: 71 tests OK. tests failed: test_cmd_line test_gdb test_smtpnet test_ssl

我该如何解决这个问题,或者至少调查发生了什么?

编辑 1--5:

已正确生成共享库:

> ls /data2/soft/openssl/lib
drwxr-xr-x engines
-rw-r--r-- libcrypto.a
lrwxrwxrwx libcrypto.so -> libcrypto.so.1.0.0
-r-xr-xr-x libcrypto.so.1.0.0
-rw-r--r-- libssl.a
lrwxrwxrwx libssl.so -> libssl.so.1.0.0
-r-xr-xr-x libssl.so.1.0.0
drwxr-xr-x pkgconfig

所以我在设置中更改了这个:

SSL=/data2/soft/openssl/
_ssl _ssl.c \                               
    -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
    $(SSL)/lib/libssl.a $(SSL)/lib/libcrypto.a -ldl

我相应地改回了 LDFLAGS/CFLAGS。但是当我运行 make clean && make 时仍然存在 -lssl,因为 _hashopen 模块:

gcc -pthread -shared -L/data2/local/lib/ -L/data2/local/lib/ -L/data2/local/lib/ -I/data2/local/include/ build/temp.linux-x86_64-3.4/data2/soft/python3/Python-3.4.0rc3/Modules/_hashopenssl.o -L/data2/local/lib/ -L/usr/local/lib -lssl -lcrypto -o build/lib.linux-x86_64-3.4/_hashlib.cpython-34m.so

我猜这是导致内核的原因,因为它们仍然存在...我尝试将类似的内容添加到安装文件中,但没有对此进行评论的项目,并且创建它会导致另一个更神秘的失败:

gcc -pthread   -Xlinker -export-dynamic -o python Modules/python.o libpython3.4m.a -lpthread -ldl  -lutil /data2/eoubrayrie/soft/openssl/lib/libssl.a /data2/eoubrayrie/soft/openssl/lib/libcrypto.a -ldl   /data2/eoubrayrie/soft/openssl/lib/libssl.a /data2/eoubrayrie/soft/openssl/lib/libcrypto.a -ldl   -lm  
libpython3.4m.a(config.o):(.data+0x158): undefined reference to `PyInit__hashopenssl'
collect2: ld returned 1 exit status

编辑 6:

  • 无论如何我都找不到修改 _hashlib.so 的生成方式,因为涉及的 Makefile 魔法太多(它没有出现在任何地方,“-lssl”也没有出现,但两者都神奇地一起出现在同一行
  • 但我可以通过旧的 -I/-L 将它动态链接到我自己的 openssl:

    ldd build/lib.linux-x86_64-3.4/_hashlib.cpython-34m.so libssl.so.1.0.0 => /data2/soft/openssl/lib/libssl.so.1.0.0 (0x00007f5605799000) libcrypto.so.1.0.0 => /data2/soft/openssl/lib/libcrypto.so.1.0.0 (0x00007f56053bd000)

  • 现在唯一的问题是,gdb info shared 仍然告诉我在核心时间使用另一个...但是如何?

    From To Syms Read Shared Object Library 0x00007ffff5465930 0x00007ffff5466e98 Yes /data2/soft/python3/Python-3.4.0rc3/build/lib.linux-x86_64-3.4/_hashlib.cpython-34m.so 0x00007ffff5321220 0x00007ffff5351878 Yes /opt/python-2.6-64/lib/libssl.so.1.0.0 0x00007ffff50d3100 0x00007ffff519b118 Yes /opt/python-2.6-64/lib/libcrypto.so.1.0.0

    • env | grep -F 'python-2.6-64' -> 什么都不显示!
    • grep -RF 'python-2.6-64' /etc/ld.so.* -> 同上
    • gcc -print-search-dirs | sed 's/:/\n/g' | grep python -> 同上
    • find . -name '*.so*' | xargs ldd | grep ssl -> 只给我好的
    • 1 级依赖项也不需要任何错误的 ssl 版本。已通过以下方式检查:
      find . -name '*.so*' | xargs ldd | awk '/\t+[[:alnum:].]+ =&gt; [[:alnum:]./]+ \(/ {print $3}' | sort | uniq | xargs ldd | grep ssl
    • strace ./python ./Tools/scripts/run_tests.py 2&gt;&amp;1 | grep python-2.6-64 -> 什么都不显示

如果ld 不知道这个库,他是如何选择这个错误的库的?它不在任何标准位置(如果它在 /lib 我可以理解...)

解决方案:

感谢this OpenOffice bug,找到了如何静态链接_hashlib:虽然-Wl,--exclude-libs=ALL" 选项也不起作用,但它为我指出了setup.py 中的正确行。

TL;DR 这是我申请的patch to setup.py

最后......它起作用了!

@noloader 我接受您最完整的答案,因为您的帮助非常宝贵,但对于遇到此问题的任何人来说,“确切”答案是使用上面的补丁进行编译。

【问题讨论】:

  • “但是 gdb 确实向我显示使用了错误的 libssl/libcrypto(系统的)” - 这通常表明首先加载了依赖项,并且该依赖项使用了错误的 OpenSSL 库。然后,当您的程序被加载时,OpenSSL 符号已从已加载的不正确版本的 OpenSSL 中得到满足。 LZMA 库是否需要libcrypto
  • 从顶级目录尝试grep -R -lssl *grep -R -lcrypto *。您也可以尝试跟踪_ssl.c_ssl.o。如果正在使用-lssl,那么grep 会找到它。就其价值而言,带有递归 makefile 的 autotools 项目给我带来的问题最多。
  • “所以我想我不明白你是如何给出完整路径的” - 请参阅下面的第二个答案(抱歉 - 第一个太长了,第二个更有针对性)。
  • "找不到 -l/data2/soft/openssl/lib/libssl.a" - 指定存档时删除 -l /data2/.../libssla.;并添加-ldl(OpenSSL 在此配置中将需要它)。
  • 你是怎么看出来的?

标签: python openssl makefile


【解决方案1】:
How can I fix this, or at least investigate what is going on ?
...
export LDFLAGS='-L/data2/soft/openssl/lib -L/data2/local/lib/'
export LD_LIBRARY_PATH="/data2/soft/openssl/lib:/data2/local/lib/

我也经常遇到这些问题,因为我避免使用 Debian、Ubuntu、Fedora 等提供的 OpenSSL 残缺版本。例如,Ubuntu 提供了一个禁用 TLSv1.1 和 TLS v1.2 的 OpenSSL(参见 Ubuntu 12.04 LTS: OpenSSL downlevel version and does not support TLS 1.2)。

您可能加载了错误版本的 OpenSSL 库。如果您可以在调试器下获得行为异常的程序,请发出 info shared 以查看您实际加载的是哪个 libcryptolibssl

ldd 也可能有帮助。在 Pyhton 可执行文件上运行它:ldd /data2/soft/python3/python。我只能说它“可能”有帮助,因为 OpenSSL 是二进制兼容的,因此您可能只会看到对 libcrypto.so.1.0.0 的依赖(在 Mac OS X 上使用 otool -L)。下面我使用rpath 来强制链接/usr/local/ssl/lib/ 中的库。

$ ldd my-test.exe 
    linux-vdso.so.1 =>  (0x00007fffd61ff000)
    libssl.so.1.0.0 => /usr/local/ssl/lib/libssl.so.1.0.0 (0x00007f151528e000)
    libcrypto.so.1.0.0 => /usr/local/ssl/lib/libcrypto.so.1.0.0 (0x00007f1514e74000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f1514c42000)
    ...

作为修复,您可以尝试添加rpath

LDFLAGS='-L/data2/soft/openssl/lib -L/data2/local/lib/ -Wl,-rpath,/data2/soft/openssl/lib'

更好的解决方法是链接到 OpenSSL 库的静态版本,以避免这些问题一起出现。我相信你可以做到这一点:-Bstatic -lssl -lcrypto -Bdynamic -ldl

就个人而言,由于不同的一次性问题,我什至不使用-Bstatic。我打开 Makefile,删除 -lssl -lcrypto 的所有实例,并添加归档的完整路径以消除所有歧义。例如,/data2/soft/openssl/lib/libssl.a/data2/soft/openssl/lib/libcrypto.a

注意rpath 在 Mac OS X 上不受支持。Mac OS X 需要更极端的措施,因为链接器也不支持 -Bstatic。您必须使用完整路径技巧。


openssl was built with ./config shared --openssldir=/data2/soft/openssl

另一件事...在 Fedora 上,指定 shared 是不够的。您还需要添加以下内容:

export CFLAGS="-fPIC"

否则,不会构建共享对象。如果未构建 1.0.1f 共享对象,您可能会获得发行版提供的低级版本。您可以检查 安装之前构建了什么:

./config shared --openssldir=/data2/soft/openssl
make all

# Verify artifacts
find . -iname -libcrypto.*
find . -iname -libssl.*

# Proceed if OK
sudo make install

最后,确保 所有 Python 的依赖项也在使用您的 OpenSSL 版本,而不是系统的 OpenSSL 版本。

我最近在我的程序使用我的 OpenSSL 时遇到了这个问题;但我的程序也使用了libeventlibevent 使用了系统的OpenSSL 版本。我通过重建 libevent 并强制它静态链接到我的 OpenSSL 版本来修复它。

【讨论】:

    【解决方案2】:

    我应该如何改变它?在任何地方添加 _ssl.c: gcc ... 行会覆盖默认行为吗?我的 Makefile 技能生锈了,这头野兽有 1600 多行!

    以下是您要查看的文件:

    $ cd Python-3.4.0rc3
    
    $ grep -R -- '-lcrypto' *
    Modules/Setup.dist:#    -L$(SSL)/lib -lssl -lcrypto
    
    $ grep -R -- '-lssl' *
    Modules/Setup.dist:#    -L$(SSL)/lib -lssl -lcrypto
    

    以下是Setup.dist 中感兴趣的行:

    # Socket module helper for SSL support; you must comment out the other
    # socket line above, and possibly edit the SSL variable:
    #SSL=/usr/local/ssl
    #_ssl _ssl.c \
    #   -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
    #   -L$(SSL)/lib -lssl -lcrypto
    

    取消注释这些行并将Setup.dist 更改为以下内容。我将我的 OpenSSL 保存在 /usr/local/ssl 中,这就是我在下面设置的方式(你应该使用 /data2/soft/openssl/lib/...):

    SSL=/usr/local/ssl
    _ssl _ssl.c \
        -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
        /usr/local/ssl/lib/libssl.a /usr/local/ssl/lib/libcrypto.a -ldl
    

    使用存档的完整路径,不要使用-l。请务必添加 -ldl,因为 OpenSSL 在此配置中需要它。

    更改Setup.dist 后,重新运行./configure 以使更改生效。


    将上面的行改为configure后的样子:

    $ grep -R "libssl.a" *
    Makefile:LOCALMODLIBS=  /usr/local/ssl/lib/libssl.a /usr/local/ssl/lib/libcrypto.a -ldl 
    Makefile:Modules/_ssl$(SO):  Modules/_ssl.o; $(BLDSHARED)  Modules/_ssl.o  /usr/local/ssl/lib/libssl.a /usr/local/ssl/lib/libcrypto.a -ldl  -o Modules/_ssl$(SO)
    Modules/Setup: /usr/local/ssl/lib/libssl.a /usr/local/ssl/lib/libcrypto.a -ldl 
    Modules/Setup.dist: /usr/local/ssl/lib/libssl.a /usr/local/ssl/lib/libcrypto.a -ldl 
    

    您可以使用lddotool -L 测试静态链接。您将不会看到 OpenSSL 依赖项。在make'ing 之后,这是我得到的:

    $ find . -iname python
    ./python
    $ ldd ./python
        linux-vdso.so.1 =>  (0x00007fff67709000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f3aed8e1000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f3aed6dd000)
        libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007f3aed4d9000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f3aed257000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3aececc000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f3aedb14000)
    

    没有 libssllibcrypto 依赖项出错:) 并且 make test 运行良好(实际上,由于 Python 错误,一个失败的测试:Issue 20896):

    ======================================================================
    ERROR: test_get_server_certificate (test.test_ssl.NetworkedTests)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/home/jwalton/Python-3.4.0rc3/Lib/test/test_ssl.py", line 1373, in test_get_server_certificate
        _test_get_server_certificate('svn.python.org', 443, SVN_PYTHON_ORG_ROOT_CERT)
      File "/home/jwalton/Python-3.4.0rc3/Lib/test/test_ssl.py", line 1354, in _test_get_server_certificate
        pem = ssl.get_server_certificate((host, port))
      File "/home/jwalton/Python-3.4.0rc3/Lib/ssl.py", line 902, in get_server_certificate
        with context.wrap_socket(sock) as sslsock:
      File "/home/jwalton/Python-3.4.0rc3/Lib/ssl.py", line 344, in wrap_socket
        _context=self)
      File "/home/jwalton/Python-3.4.0rc3/Lib/ssl.py", line 540, in __init__
        self.do_handshake()
      File "/home/jwalton/Python-3.4.0rc3/Lib/ssl.py", line 767, in do_handshake
        self._sslobj.do_handshake()
    ssl.SSLError: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:598)
    
    ----------------------------------------------------------------------
    Ran 96 tests in 8.610s
    
    FAILED (errors=1, skipped=3)
    test test_ssl failed
    make: *** [test] Error 1
    

    【讨论】:

      【解决方案3】:

      这不是答案,只是与您一起运行后的观察:

      $ make 
      ...
      
      gcc -pthread -c -Wno-unused-result -Werror=declaration-after-statement
        -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -I. -IInclude -I./Include
        -DPy_BUILD_CORE -o Objects/capsule.o Objects/capsule.c
      

      -fwrapv 真的很糟糕。它用于使非法程序工作。最好修复损坏的程序并删除-fwrapv。请参阅 Signed Overflow 上的 Ian Lance Taylor 的博客。

      【讨论】:

      【解决方案4】:

      无论如何我都找不到修改 _hashlib.so 的生成方式,因为涉及的 Makefile 魔法太多(它没有出现在任何地方,'-lssl' 也没有出现,但两者都神奇地一起出现在同一行

      grep 是你的朋友 ;)

      $ grep -R _hashlib * | grep ssl
      Lib/hashlib.py:        f = getattr(_hashlib, 'openssl_' + name)
      Lib/hashlib.py:            _hashlib.openssl_md_meth_names)
      Lib/test/test_hashlib.py:            self.assertTrue(hasattr(_hashlib, 'openssl_md5'))
      Lib/test/test_hashlib.py:            self.assertTrue(hasattr(_hashlib, 'openssl_sha1'))
      Lib/test/test_hashlib.py:                constructor = getattr(_hashlib, 'openssl_'+algorithm, None)
      Lib/test/ssltests.py:TESTS = ['test_asyncio', 'test_ftplib', 'test_hashlib', 'test_httplib',
      Lib/test/time_hashlib.py:    print(" '_hashlib' 'openssl_hName' 'fast' tests the builtin _hashlib")
      Modules/_hashopenssl.c:    "_hashlib.HASH",    /*tp_name*/
      Modules/_hashopenssl.c:static struct PyModuleDef _hashlibmodule = {
      Modules/_hashopenssl.c:    "_hashlib",
      Modules/_hashopenssl.c:PyInit__hashlib(void)
      Modules/_hashopenssl.c:    m = PyModule_Create(&_hashlibmodule);
      PCbuild/build_ssl.py:# Script for building the _ssl and _hashlib modules for Windows.
      PCbuild/build_ssl.py:# for the actual _ssl.pyd and _hashlib.pyd DLLs.
      PCbuild/build_ssl.py:# it should configure and build SSL, then build the _ssl and _hashlib
      setup.py:                exts.append( Extension('_hashlib', ['_hashopenssl.c'],
      setup.py:                print("warning: openssl 0x%08x is too old for _hashlib" %
      Tools/ssl/test_multiple_versions.py:    "test_asyncio", "test_ftplib", "test_hashlib", "test_httplib",
      Tools/ssl/test_multiple_versions.py:MINIMAL_TESTS = ["test_ssl", "test_hashlib"]
      

      【讨论】:

        【解决方案5】:

        另一个部分答案...

        但我可以通过旧的 -I/-L 将它动态链接到我自己的 openssl:

        ...

        现在唯一的问题是,gdb info shared 仍然告诉我另一个在核心时使用...但是如何?

        那是你们的好老朋友-l-L不要使用它们,因为它们一直在做这种事情(从过去遭受过这种情况的人那里拿走)。而是指定libssllibcrypto完整 路径。例如,使用/data2/soft/openssl/lib/libssl.a

        【讨论】:

        • 显然我更喜欢它,但是设置更改不适用于 _hashlib,而且我无法了解如何将 -lssl 添加到 _hashlib 编译或如何在 Makefile 中对其进行自定义。也没有人在网上提到过它:-(
        【解决方案6】:

        我们遇到了类似的问题。我们使用apache httpd + mod_wsgi + python + django 和我们的apache httpd 的c++ 模块,它也使用openssl。现在所有内容都在一个httpd 进程中加载​​,正确版本的openssl 共享库已使用我们的c++ 模块加载(1.0.0l)。但是一旦我们访问网络,python 就会加载 hashlib 并出现完全相同的问题 - 从 python 调用的 openssl 中的段错误。

        通常,python 会使用 默认位置 提供的任何openssl 进行编译,如果不摆弄setup.py 或makefile,就无法指定它。 Python 开发者应添加配置设置--with_ssl=path

        我们安装了新的 openssl 库并重建了 python 和其他二进制文件,但没有成功。我们将默认的 libssl.so 和 libcrypto.so 映射到新的 openssl 二进制文件,但没有成功。最后在阅读了这个帖子之后,我意识到编译 python 时可能使用了错误的头文件。这就是问题所在。按照以下步骤解决问题:

        • /usr/include 和默认位置/usr/local/ssl/usr/contrib/ssl 中不能有错误版本的openssl 标头(如果您安装了openssl-devel,则将其卸载,或者只是擦除/重命名目录)

        yum remove openssl-devel

        • /usr/local/ssl创建指向您的openssl安装的符号链接

        ln -s /opt/openssl-1.0.1l /usr/local/ssl

        • 确保可以从 /usr/lib 访问新的 openssl 库(如果此处未安装,请创建符号链接)

        ln -s /opt/openssl-1.0.1l/lib/libcrypto.so.1.0.0 /usr/lib/libcrypto.so.1.0.0 ...

        • 现在配置和清理构建python

        【讨论】:

        • 为 python 提供了一个新的配置选项 --with-ssl 的补丁(希望它会发布):bugs.python.org/issue21541
        • 你的补丁已经合并到 Python master 中了吗?
        • @dex:从那以后我没有检查过...查看当前版本 3.5 我找不到那个,没有--with-ssl 选项
        【解决方案7】:

        在此处提到https://gist.github.com/eddy-geek/9604982 进行修补修复后,我可以使用非默认 SSL 运行 python 2.7.11

        但是,它并没有构建许多其他模块所需的 _socket 模块。例如,easy_install / pip 开始失败并出现错误 Importerr: no module named _socket

        在 Module/Setup.dist 中,我是否应该取消注释或注释该行 _socket socketmodule.o ?

        我看到 socketmodule.o 和 timemodule.o 正在生成。但不是 _socket.so 我错过了什么吗?

        【讨论】:

        • 不知道,我最近没有使用这个补丁......你可能应该问一个新问题(带有指向这个问题的链接)
        • 实际上,在 Modules/Setup.dist 中注释掉“_socket socketmodule.c timemodule.c”行可以解决这个问题。确保模块/设置也反映了这一变化。
        猜你喜欢
        • 2014-06-26
        • 2018-09-07
        • 1970-01-01
        • 2017-05-13
        • 1970-01-01
        • 2021-07-11
        • 2021-05-22
        • 1970-01-01
        • 2016-03-20
        相关资源
        最近更新 更多