从共享库中安全调用 openSSL 函数
Safely call openSSL functions from inside a shared library
我已经实现了一个客户端程序,它使用 openSSL 以安全的方式连接到服务器。客户端被编译为共享对象 (SO),以便第三方应用程序可以加载它并连接到服务器。 (注意:SO 的编译方式使得 openSSL 静态链接到它。[如果知道这对您的答案有影响])
它在许多应用程序中都能正常工作。但是,如果第三方应用程序本身出于任何其他原因加载 openSSL,则当库尝试调用 SSL_library_init()
时会发生分段错误。看来,两次调用不可重入函数 SSL_library_init()
会导致分段错误。第一次调用发生在主程序中,第二次调用由我的共享对象触发。
有什么方法可以解决这个问题吗?例如,通过分离 SSL_library_init()
的 main 和 SO 调用并强制 SO 在单独的内存中调用函数 space?或者,使用 objcopy --prefix-symbols=...
命令重命名 openSSL 的符号名称?
总而言之,当我不知道什么程序会加载这个库时,是否可以从共享库中安全地调用不可重入函数SSL_library_init
?
显然,我无法控制第三方应用程序。所以,我无法确定它应该在何处以及如何调用该函数。
However, if the third party application itself loads openSSL for any
other reason, a segmentation fault occurs when the library tries to
invoke SSL_library_init()
.
这听起来不像是重入问题,因为我看不出客户端应用程序如何导致 SSL_library_init()
重入。因此,我倾向于认为文档使用了错误的术语。我怀疑他们的意思是 SSL_library_init()
不是线程安全的,或者可能只是不能多次调用它。
It works fine in many applications. However, if the third party
application itself loads openSSL for any other reason, a segmentation
fault occurs when the library tries to invoke SSL_library_init(). It
seems that, calling the non-reentrant function SSL_library_init()
twice, leads to the segmentation fault. The first call occurs in the
main program and the second invocation triggers by my shared object.
这可能反映了您的设计限制,与将标准 OpenSSL 捆绑到您的共享库有关。这样做会产生很大的风险,即应用程序将动态 link OpenSSL 的两份副本,一份以其标准共享库的形式存在,另一份包含在您的共享库中。虽然这不会自动意味着生成的程序会中断,但它确实为中断开辟了多种途径。
特别是,将 OpenSSL 的多个副本 link 编辑到应用程序中可能会导致一个副本的某些函数调用函数或访问属于另一个副本的外部对象。尽管如此,您仍然可以摆脱它,但即使在 OpenSSL 的两个副本是完全相同的版本、使用相同的选项构建的情况下,也有多种方法会出错。随着两个副本的版本或构建选项不同,可能性会扩大。
Is there any method to solve this problem? For example, by separating
the main and SO calls of SSL_library_init() and enforcing SO to call
the function in a separate memory space?
我能想到的提供“独立内存space”的主要方法是启动一个子进程。事实上,我可以看到围绕您的 SO 提供一个瘦包装程序来达到这个目的,并且可以想象它会更普遍地有用。但请注意,这不是所提出问题的解决方案,而是一种解决方法。这可能完全没问题。
Or, by renaming symbol names
of openSSL using something like objcopy --prefix-symbols=... command?
修改捆绑的 OpenSSL 副本公开的所有外部符号听起来是一个很有前途的选择,但我会在 (OpenSSL) 构建时进行,而不是在构建后尝试修改 SO。
In summary, is it possible to safely call the non-reentrant function
SSL_library_init from inside a shared library when I do not know what
programs will load this library?
同样,我认为重入不是问题所在。线程安全可能是一个问题,或者可能存在围绕动态 linking 细节的问题。通过更好地将 OpenSSL 的捆绑副本与客户端应用程序隔离, 和 客户端应用程序与捆绑的 OpenSSL 更好地隔离,可能会解决其中任何一个问题。当你只控制一个组件时,我能想到的最好的方法是更改符号名称以避免冲突。
Self-response:
设置-fvisibility=hidden
在openSSL的编译过程中对外部模块隐藏openSSL的内部符号。
或
编译 SO 时使用 -Wl,--exclude-libs,ALL
。例如:g++ -shared -o mylib.so obj1.o obj2.o -L/path/to/openssl/static-libs -lssl -lcrypto -Wl,--exclude-libs,ALL
我更喜欢第二种方法,因为它也解决了openssl引擎版本冲突的问题(至少在我的情况下)。
我已经实现了一个客户端程序,它使用 openSSL 以安全的方式连接到服务器。客户端被编译为共享对象 (SO),以便第三方应用程序可以加载它并连接到服务器。 (注意:SO 的编译方式使得 openSSL 静态链接到它。[如果知道这对您的答案有影响])
它在许多应用程序中都能正常工作。但是,如果第三方应用程序本身出于任何其他原因加载 openSSL,则当库尝试调用 SSL_library_init()
时会发生分段错误。看来,两次调用不可重入函数 SSL_library_init()
会导致分段错误。第一次调用发生在主程序中,第二次调用由我的共享对象触发。
有什么方法可以解决这个问题吗?例如,通过分离 SSL_library_init()
的 main 和 SO 调用并强制 SO 在单独的内存中调用函数 space?或者,使用 objcopy --prefix-symbols=...
命令重命名 openSSL 的符号名称?
总而言之,当我不知道什么程序会加载这个库时,是否可以从共享库中安全地调用不可重入函数SSL_library_init
?
显然,我无法控制第三方应用程序。所以,我无法确定它应该在何处以及如何调用该函数。
However, if the third party application itself loads openSSL for any other reason, a segmentation fault occurs when the library tries to invoke
SSL_library_init()
.
这听起来不像是重入问题,因为我看不出客户端应用程序如何导致 SSL_library_init()
重入。因此,我倾向于认为文档使用了错误的术语。我怀疑他们的意思是 SSL_library_init()
不是线程安全的,或者可能只是不能多次调用它。
It works fine in many applications. However, if the third party application itself loads openSSL for any other reason, a segmentation fault occurs when the library tries to invoke SSL_library_init(). It seems that, calling the non-reentrant function SSL_library_init() twice, leads to the segmentation fault. The first call occurs in the main program and the second invocation triggers by my shared object.
这可能反映了您的设计限制,与将标准 OpenSSL 捆绑到您的共享库有关。这样做会产生很大的风险,即应用程序将动态 link OpenSSL 的两份副本,一份以其标准共享库的形式存在,另一份包含在您的共享库中。虽然这不会自动意味着生成的程序会中断,但它确实为中断开辟了多种途径。
特别是,将 OpenSSL 的多个副本 link 编辑到应用程序中可能会导致一个副本的某些函数调用函数或访问属于另一个副本的外部对象。尽管如此,您仍然可以摆脱它,但即使在 OpenSSL 的两个副本是完全相同的版本、使用相同的选项构建的情况下,也有多种方法会出错。随着两个副本的版本或构建选项不同,可能性会扩大。
Is there any method to solve this problem? For example, by separating the main and SO calls of SSL_library_init() and enforcing SO to call the function in a separate memory space?
我能想到的提供“独立内存space”的主要方法是启动一个子进程。事实上,我可以看到围绕您的 SO 提供一个瘦包装程序来达到这个目的,并且可以想象它会更普遍地有用。但请注意,这不是所提出问题的解决方案,而是一种解决方法。这可能完全没问题。
Or, by renaming symbol names of openSSL using something like objcopy --prefix-symbols=... command?
修改捆绑的 OpenSSL 副本公开的所有外部符号听起来是一个很有前途的选择,但我会在 (OpenSSL) 构建时进行,而不是在构建后尝试修改 SO。
In summary, is it possible to safely call the non-reentrant function SSL_library_init from inside a shared library when I do not know what programs will load this library?
同样,我认为重入不是问题所在。线程安全可能是一个问题,或者可能存在围绕动态 linking 细节的问题。通过更好地将 OpenSSL 的捆绑副本与客户端应用程序隔离, 和 客户端应用程序与捆绑的 OpenSSL 更好地隔离,可能会解决其中任何一个问题。当你只控制一个组件时,我能想到的最好的方法是更改符号名称以避免冲突。
Self-response:
设置-fvisibility=hidden
在openSSL的编译过程中对外部模块隐藏openSSL的内部符号。
或
编译 SO 时使用 -Wl,--exclude-libs,ALL
。例如:g++ -shared -o mylib.so obj1.o obj2.o -L/path/to/openssl/static-libs -lssl -lcrypto -Wl,--exclude-libs,ALL
我更喜欢第二种方法,因为它也解决了openssl引擎版本冲突的问题(至少在我的情况下)。