我有一个现有的预建的
.so
共享库(让我们称之为
libjniopenssl.so
)。它是由第三方在
Debian Linux
上用
OpenSSL 1.0.1k-3+deb8u4
构建的。
我不得不在
CentOS
上运行
OpenSSL 1.0.2k
包的
libjniopenssl.so
。
尽管
OpenSSL
的版本略有不同,但
libjniopenssl.so
所使用的API在
1.0.1k
和
1.0.2k
之间没有改变。- 所以我希望它们在我的方案中是源代码和二进制兼容的。
不幸的是,仅仅在
CentOS
上运行
libjniopenssl.so
并不能工作。
替换代码1】通过
System.loadLibrary
被
JVM
加载,但在
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
原因很简单,在CentOS
上没有这样的文件libcrypto.so.1.0.0
,因为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
包特意改名替换代码0】的文件名从默认的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
。
This resulted in the following error in run-time:
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
版本的OpenSSL 1.0.1k
有包括许多补丁, including one which 增加了符号版本管理.它只在OpenSSL 1.1.0
中被引入,但被提供Debian软件包的人移植到1.0.1
。
相反,【替换代码5替换代码6】包不包括那个用于符号版本的补丁(但它们包括来自1.1.0
的、符合.so
中的符号的其他补丁)。
我可以在CentOS
上针对它的OpenSSL
的副本重新构建libjniopenssl.so
,但这实际上涉及到维护(构建。存储、部署)自己的libjniopenssl.so
的副本,而这个副本实际上来自第三方的git仓库。我不喜欢重建方案,所以我在寻找更优雅的方案。但我不得不说re-building是CentOS
论坛上的推荐。
我能想到的一个解决方案是在构建或部署时生成一个特殊的 shim libcrypto.so.1.0.0
(基于目标系统提供的libcrypto
的副本),它按照libjniopenssl.so
的要求重命名了符号。但在引擎盖下,它将翻译所有对原始系统提供的libcrypto.so.1.0.2k
的调用。
总的来说,我在寻找一些工具或工具集,能够从指定的 "实现".so
中自动生成这样的 "shim/adapter/proxy".so
,但能够重新定义一些或所有符号。
我发现有objcopy
的工具有--redefine-symbol old=new
,但它并不完全能做到我想要的。我不想从原始的.so
中复制任何代码,我想翻译对原始 "实现 "的.so
的调用。
UPD:通过运行本地实验,发现objcopy
不支持动态库中的符号重命名。从这个问题可以看出邮件主题.
综上所述,我的问题是。
Is there an existing util capable to generate such shared shim library for a specified .so
file?
Or maybe there is a better way to solve this incompatibility between CentOS
and Debian
OpenSSL
packages, assuming I don't want to modify neither third-party provided libjniopenssl.so
nor OS provided copy of OpenSSL
?