首页 > 解决方案 > 从共享库中安全地调用 openSSL 函数

问题描述

我已经实现了一个客户端程序,它使用 openSSL 以安全的方式连接到服务器。客户端被编译为共享对象 (SO),以便第三方应用程序可以加载它并连接到服务器。(注意:SO 的编译方式使得 openSSL 静态链接到它。[如果知道这对您的答案有影响])

它在许多应用程序中都能正常工作。但是,如果第三方应用程序本身出于任何其他原因加载 openSSL,则当库尝试调用SSL_library_init(). 似乎,SSL_library_init()两次调用不可重入函数会导致分段错误。第一次调用发生在主程序中,第二次调用由我的共享对象触发。

有什么方法可以解决这个问题吗?例如,通过分离 main 和 SO 调用SSL_library_init()并强制 SO 在单独的内存空间中调用函数?objcopy --prefix-symbols=...或者,通过使用类似命令的方式重命名 openSSL 的符号名称?

总之,SSL_library_init当我不知道哪些程序会加载这个库时,是否可以从共享库中安全地调用不可重入函数?

显然,我无法控制第三方应用程序。所以,我无法确定它应该在哪里以及如何调用该函数。

标签: copenssllinkershared-libraries

解决方案


但是,如果第三方应用程序本身出于任何其他原因加载 openSSL,则当库尝试调用SSL_library_init().

这听起来不像是重入问题,因为我看不到客户端应用程序如何导致重入SSL_library_init()。因此,我倾向于认为文档使用了错误的术语。我怀疑他们的意思是这SSL_library_init()不是线程安全的,或者可能只是不能多次调用它。

它在许多应用程序中都能正常工作。但是,如果第三方应用程序本身出于任何其他原因加载 openSSL,则当库尝试调用 SSL_library_init() 时会发生分段错误。看来,调用不可重入函数 SSL_library_init() 两次会导致分段错误。第一次调用发生在主程序中,第二次调用由我的共享对象触发。

这可能反映了您设计的限制,与将标准 OpenSSL 捆绑到您的共享库中有关。这样做会产生很大的风险,即应用程序将动态链接 OpenSSL 的两个副本,一个以其标准共享库的形式,一个包含在您的共享库中。尽管这并不意味着生成的程序会自动中断,但它确实开辟了多种破坏途径。

特别是,将多个 OpenSSL 副本链接到应用程序可能会导致一个副本的某些功能调用函数或访问属于另一个副本的外部对象。尽管如此,您仍然可以侥幸逃脱,但即使在 OpenSSL 的两个副本是完全相同的版本、使用相同的选项构建的情况下,也有多种方法会出错。随着两个副本的版本或构建选项的不同,可能性会扩大。

有什么方法可以解决这个问题吗?例如,通过分离 SSL_library_init() 的 main 和 SO 调用并强制 SO 在单独的内存空间中调用该函数?

我能想到的提供“独立内存空间”的主要方法是启动一个子进程。事实上,我可以看到围绕您的 SO 提供一个瘦包装程序来实现此目的,并且可以想象它会更普遍地有用。但请注意,这不是解决问题的方法,而是一种解决方法。这可能完全没问题。

或者,通过使用 objcopy --prefix-symbols=... 命令重命名 openSSL 的符号名称?

修改 OpenSSL 捆绑副本公开的所有外部符号听起来是一个很有前途的选择,但我会在(OpenSSL)构建时这样做,而不是在构建后尝试修改 SO。

总之,当我不知道哪些程序会加载这个库时,是否可以从共享库中安全地调用不可重入函数 SSL_library_init?

同样,我认为重入不是问题。线程安全可能是一个问题,或者可能存在围绕动态链接细节的问题。通过更好地将捆绑的 OpenSSL 副本与客户端应用程序以及客户端应用程序与捆绑的 OpenSSL隔离开来,可能会解决其中任何一个问题。当您只控制一个组件时,我能想到的实现这两个方面的最佳方法是更改​​符号名称以避免冲突。


推荐阅读