生成匀场片“ .so”以重命名现有“ .so”的符号

时间:2019-01-03 10:14:58

标签: java linux openssl centos debian

我有一个现有的预建.so共享库(我们叫它libjniopenssl.so)。它是由第三方在Debian LinuxOpenSSL 1.0.1k-3+deb8u4上构建的。 我必须使用libjniopenssl.so软件包在CentOS上运行OpenSSL 1.0.2k。 尽管OpenSSL的版本略有不同,libjniopenssl.so使用的API在1.0.1k1.0.2k之间未更改-因此,我希望它们在我的方案中是源代码和二进制兼容的。 不幸的是,仅在libjniopenssl.so上运行CentOS无效。

libjniopenssl.soJVM通过System.loadLibrary加载,但是在CentOS上运行时失败,并显示以下错误:

Unable to load libjniopenssl: java.lang.UnsatisfiedLinkError: /tmp/jna-112200956/jna6604950569974562639.tmp:
libcrypto.so.1.0.0: cannot open shared object file: No such file or directory

原因很简单,libcrypto.so.1.0.0上没有这样的文件CentOS,因为OpenSSL 1.0.2k 16.el7仅提供以下.so的文件:

$ ls -l /lib64/libcrypto*
lrwxrwxrwx. 1 root root      19 Jun  5  2018 /lib64/libcrypto.so.10 -> libcrypto.so.1.0.2k
-rwxr-xr-x. 1 root root 2512832 Apr 11  2018 /lib64/libcrypto.so.1.0.2k

由于某种原因,CentOSintentionally renamed .so的文件名从默认libcrypto.so.1.0.0打包为libcrypto.so.1.0.2k,即使从source编译该版本它使用名称libcrypto.so.1.0.0

此错误消息建议尝试创建名称为/lib64/libcrypto.so.1.0.0的符号链接,该链接指向/lib64/libcrypto.so.1.0.2k

这在运行时导致以下错误:

Unable to load libjniopenssl: java.lang.UnsatisfiedLinkError: /tmp/jna-112200956/jna2564265718506275007.tmp: 
/lib64/libcrypto.so.1.0.0: version `OPENSSL_1.0.0' not found (required by /tmp/jna-112200956/jna2564265718506275007.tmp)

检查libjniopenssl.so显示有OpenSSL引用的以下符号:

$ readelf -Ws libjniopenssl.so

Symbol table '.dynsym' contains 40 entries:
Num:    Value          Size Type    Bind   Vis      Ndx Name
    0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
    1: 0000000000000e98     0 SECTION LOCAL  DEFAULT    9
    2: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    3: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _Jv_RegisterClasses
    4: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND EVP_CIPHER_CTX_init@OPENSSL_1.0.0 (2)
    5: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND malloc@GLIBC_2.2.5 (3)
    6: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND OPENSSL_add_all_algorithms_noconf@OPENSSL_1.0.0 (2)
    7: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND HMAC_CTX_cleanup@OPENSSL_1.0.0 (2)
    8: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND EVP_CipherUpdate@OPENSSL_1.0.0 (2)
    9: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterTMCloneTable
    10: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND ERR_load_crypto_strings@OPENSSL_1.0.0 (2)
    11: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND free@GLIBC_2.2.5 (3)
    12: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMCloneTable
    13: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@GLIBC_2.2.5 (3)
    14: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND HMAC_CTX_init@OPENSSL_1.0.0 (2)
    15: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND HMAC_Final@OPENSSL_1.0.0 (2)
    16: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND EVP_sha1@OPENSSL_1.0.0 (2)
    17: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND HMAC_Init_ex@OPENSSL_1.0.0 (2)
    18: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND HMAC_Update@OPENSSL_1.0.0 (2)
    19: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND EVP_CIPHER_CTX_cleanup@OPENSSL_1.0.0 (2)
    20: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND EVP_MD_size@OPENSSL_1.0.0 (2)
    21: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND EVP_aes_128_ctr@OPENSSL_1.0.1 (4)

但是libcrypto.so.1.0.2k上的CentOS具有带有不同后缀的符号,例如:

readelf -Ws /lib64/libcrypto.so.1.0.2k | grep -iE "EVP_CIPHER_CTX_init"
705: 000000000012a6b0   151 FUNC    GLOBAL DEFAULT   13 EVP_CIPHER_CTX_init@@libcrypto.so.10

因此,在CentOS上,后缀为@@libcrypto.so.10,但是libjniopenssl.so被链接到共享库,后者的后缀为@OPENSSL_1.0.0。这可能就是为什么仅添加符号链接不起作用的原因。

进一步的调查显示Debian的{​​{1}}版本具有included many patches,其中包括adds symbol versioning。它仅在OpenSSL 1.0.1k中引入,但后来被提供Debian软件包的人移植到OpenSSL 1.1.0

相反,1.0.1 CentOS软件包不包含用于符号版本控制的补丁(但根据OpenSSL 1.0.2k中的符号,它们包括1.1.0中的其他补丁)。

我可以针对.so的副本在libjniopenssl.so上重建CentOS,但这实际上涉及维护(构建,存储,部署)自己的OpenSSL副本,实际上来自第三方git存储库。我不喜欢重建解决方案,因此我正在寻找更优雅的解决方案。但是我不得不说re-buildinglibjniopenssl.so论坛上的推荐内容。

我可以想到的一种解决方案是在构建或部署期间生成特殊的垫片CentOS(基于目标系统提供的libcrypto.so.1.0.0副本),该垫片已根据{{1}的需要重命名了符号},但在幕后它会将所有呼叫转换为系统提供的原始libcrypto

一般来说,我正在寻找一些能够从指定的“实现” libjniopenssl.so中自动生成这样的“垫片/适配器/代理” libcrypto.so.1.0.2k的工具或工具集,但是重新定义部分或全部符号的能力。 我发现有.so个工具,其中有.so,但它并不能完全满足我的要求:我不想复制原始objcopy中的任何代码,我确实希望将调用转换为原始的“实现” --redefine-symbol old=new

UPD :运行本地实验是由于.so不支持动态库中符号的重命名。此mail thread确认的问题。

总而言之,我的问题是:

  1. 是否有现有的util能够为指定的.so文件生成这样的共享填充库?
  2. 或者,也许有更好的方法来解决objcopy.so CentOS软件包之间的不兼容性,假设我不想修改任何第三方提供的{{1} }还是操作系统没有提供Debian的副本?

0 个答案:

没有答案