使用自定义openssl版本编译python时的Coredump

时间:2014-03-14 15:19:45

标签: python openssl makefile

使用本地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 lib的自定义位置
  • 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

所以我在Setup中更改了这个:

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&amp;&amp; amp; make,因为_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' - &gt;什么都没显示!
    • grep -RF 'python-2.6-64' /etc/ld.so.* - &gt;同上
    • gcc -print-search-dirs | sed 's/:/\n/g' | grep python - &gt;同上
    • find . -name '*.so*' | xargs ldd | grep ssl - &gt;只给我好的
    • 1级依赖项也不需要任何错误的ssl版本。检查结果如下:
      find . -name '*.so*' | xargs ldd | awk '/\t+[[:alnum:].]+ => [[:alnum:]./]+ \(/ {print $3}' | sort | uniq | xargs ldd | grep ssl
    • strace ./python ./Tools/scripts/run_tests.py 2>&1 | grep python-2.6-64 - &gt;没有显示

那么ld如果他不能知道这个错误的库怎么选?它不在任何标准位置(如果它在/ lib中我能理解......)

解决方案:

通过this OpenOffice bug找到了如何静态链接_hashlib:虽然-Wl,--exclude-libs=ALL"选项也不起作用,但它指向了setup.py中的右侧行。

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

最后......它有效!

@noloader我接受你最完整的答案,因为你的帮助是非常宝贵的,尽管遇到这个问题的人的“确切”答案是使用上面的补丁进行编译。

7 个答案:

答案 0 :(得分:3)

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

注意:在Mac OS X上不支持rpath。对于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版本来修复它。

答案 1 :(得分:3)

  

我该如何改变呢?是否会在任何地方添加_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之后,这就是我得到的:

$ 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

答案 2 :(得分:1)

这不是一个答案,只是在跟你跑完之后的一个观察结果:

$ 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的博客。

答案 3 :(得分:0)

  

我无法找到修改_hashlib.so的生成方式,因为涉及太多的Makefile魔法(它不会出现在任何地方,也不会出现-lssl&#39;两者神奇地结束在同一条线上

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"]

答案 4 :(得分:0)

另一个部分答案......

  

但我可以通过良好的旧-I / -L:

动态链接到我自己的openssl      

...

     

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

那是你的老朋友-l-L不要使用它们因为它们总是这样做(从过去遭受过它的人那里拿走它)。而是指定{em>完整路径libssllibcrypto。例如,使用/data2/soft/openssl/lib/libssl.a

答案 5 :(得分:0)

我们遇到了类似的问题。我们正在使用apache httpd + mod_wsgi + python + djangoapache httpd的c ++模块,它们也使用openssl。现在一切都在一个httpd进程中加载​​,正确版本的openssl共享库被加载(1.0.0l)与我们的c ++模块。但是一旦我们访问网页,python就会加载hashlib并出现完全相同的问题 - 来自python的openssl中的segfault。

正常情况下,python会使用默认位置时可用的openssl进行编译,并且无法在不使用setup.py或makefiles的情况下指定它。 Python开发人员应添加配置设置--with_ssl=path

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

  • openssl和默认位置/usr/include/usr/local/ssl中的/usr/contrib/ssl标题不得错误(如果您安装了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

答案 6 :(得分:0)

我可以在修补此处提到的修补程序https://gist.github.com/eddy-geek/9604982后运行带有非默认SSL的python 2.7.11

但是,由于它没有构建许多其他模块所需的_socket模块。例如,easy_install / pip启动失败,错误导入器:没有名为_socket的模块

在Module / Setup.dist中,我想取消注释或评论该行 _socket socketmodule.o ?

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