我有一个现有的预建.so
共享库(我们叫它libjniopenssl.so
)。它是由第三方在Debian Linux
和OpenSSL 1.0.1k-3+deb8u4
上构建的。
我必须使用libjniopenssl.so
软件包在CentOS
上运行OpenSSL 1.0.2k
。
尽管OpenSSL
的版本略有不同,libjniopenssl.so
使用的API在1.0.1k
和1.0.2k
之间未更改-因此,我希望它们在我的方案中是源代码和二进制兼容的。
不幸的是,仅在libjniopenssl.so
上运行CentOS
无效。
libjniopenssl.so
由JVM
通过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
由于某种原因,CentOS
将intentionally 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-building是libjniopenssl.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确认的问题。
总而言之,我的问题是:
.so
文件生成这样的共享填充库? objcopy
和.so
CentOS
软件包之间的不兼容性,假设我不想修改任何第三方提供的{{1} }还是操作系统没有提供Debian
的副本?