【问题标题】:Safely call openSSL functions from inside a shared library从共享库中安全地调用 openSSL 函数
【发布时间】:2020-08-10 06:32:53
【问题描述】:

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

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

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

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

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

【问题讨论】:

    标签: c openssl linker shared-libraries


    【解决方案1】:

    但是,如果第三方应用程序本身为任何 其他原因,当库试图 调用SSL_library_init()

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

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

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

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

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

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

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

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

    综上所述,是否可以安全地调用不可重入函数 当我不知道是什么时,来自共享库中的 SSL_library_init 程序会加载这个库吗?

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

    【讨论】:

    • 因此,主要问题似乎是“将多个 OpenSSL 副本链接到应用程序”,这“可能导致一个副本的某些功能调用函数或访问属于另一个副本的外部对象副本”,如回复中所述。感谢您的准确解释。根据这个回复,我更正了标题并将其从“从共享库中安全调用SSL_library_init等不可重入函数”更改为“从共享库中安全调用openSSL函数”。
    【解决方案2】:

    自我反应:

    在openSSL的编译过程中设置-fvisibility=hidden对外部模块隐藏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引擎上的版本冲突问题(至少在我的情况下)。

    【讨论】:

      猜你喜欢
      • 2011-02-02
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-22
      • 1970-01-01
      • 2021-02-26
      • 1970-01-01
      相关资源
      最近更新 更多