首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用shared_ptr进行private_key故障分割

使用shared_ptr进行private_key故障分割
EN

Stack Overflow用户
提问于 2021-02-05 17:47:49
回答 3查看 3.5K关注 0票数 50

更新TLS::credentials creds在全局范围内声明时,我发现了这种情况,但是如果我在seg之外声明它,那么seg故障就不会发生。 我需要它是全局的,因为它有助于缓存证书,并且多个线程可以使用其他线程创建的证书,而无需花费时间创建新的证书。 X进一步减少了代码,从200行左右。转到100行

我使用Botan创建了一个TLS应用程序,我的应用程序在应用程序的末尾出现了一个seg故障。

我试着用Val差尔调试它,但是它没有结果。

这是瓦伦的堆栈追踪,

代码语言:javascript
复制
==3841967== Invalid write of size 8
==3841967==    at 0x4842964: memset (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==3841967==    by 0x566A82F: Botan::deallocate_memory(void*, unsigned long, unsigned long) (in /usr/lib/x86_64-linux-gnu/libbotan-2.so.12.12.1)
==3841967==    by 0x55E1A4D: ??? (in /usr/lib/x86_64-linux-gnu/libbotan-2.so.12.12.1)
==3841967==    by 0x40EC7B: std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() (shared_ptr_base.h:155)
==3841967==    by 0x40EC29: std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() (shared_ptr_base.h:730)
==3841967==    by 0x41112D: std::__shared_ptr<Botan::RSA_Public_Data const, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() (shared_ptr_base.h:1169)
==3841967==    by 0x411107: std::shared_ptr<Botan::RSA_Public_Data const>::~shared_ptr() (shared_ptr.h:103)
==3841967==    by 0x41109D: Botan::RSA_PublicKey::~RSA_PublicKey() (rsa.h:25)
==3841967==    by 0x410FC1: Botan::RSA_PrivateKey::~RSA_PrivateKey() (rsa.h:92)
==3841967==    by 0x410DC5: Botan::RSA_PrivateKey::~RSA_PrivateKey() (rsa.h:92)
==3841967==    by 0x410E8A: std::_Sp_counted_ptr<Botan::RSA_PrivateKey*, (__gnu_cxx::_Lock_policy)2>::_M_dispose() (shared_ptr_base.h:377)
==3841967==    by 0x40EC7B: std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() (shared_ptr_base.h:155)
==3841967==  Address 0x9419080 is not stack'd, malloc'd or (recently) free'd
==3841967== 
==3841967== 
==3841967== Process terminating with default action of signal 11 (SIGSEGV)
==3841967==  Access not within mapped region at address 0x9419080
==3841967==    at 0x4842964: memset (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==3841967==    by 0x566A82F: Botan::deallocate_memory(void*, unsigned long, unsigned long) (in /usr/lib/x86_64-linux-gnu/libbotan-2.so.12.12.1)
==3841967==    by 0x55E1A4D: ??? (in /usr/lib/x86_64-linux-gnu/libbotan-2.so.12.12.1)
==3841967==    by 0x40EC7B: std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() (shared_ptr_base.h:155)
==3841967==    by 0x40EC29: std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() (shared_ptr_base.h:730)
==3841967==    by 0x41112D: std::__shared_ptr<Botan::RSA_Public_Data const, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() (shared_ptr_base.h:1169)
==3841967==    by 0x411107: std::shared_ptr<Botan::RSA_Public_Data const>::~shared_ptr() (shared_ptr.h:103)
==3841967==    by 0x41109D: Botan::RSA_PublicKey::~RSA_PublicKey() (rsa.h:25)
==3841967==    by 0x410FC1: Botan::RSA_PrivateKey::~RSA_PrivateKey() (rsa.h:92)
==3841967==    by 0x410DC5: Botan::RSA_PrivateKey::~RSA_PrivateKey() (rsa.h:92)
==3841967==    by 0x410E8A: std::_Sp_counted_ptr<Botan::RSA_PrivateKey*, (__gnu_cxx::_Lock_policy)2>::_M_dispose() (shared_ptr_base.h:377)
==3841967==    by 0x40EC7B: std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() (shared_ptr_base.h:155)
==3841967==  If you believe this happened as a result of a stack
==3841967==  overflow in your program's main thread (unlikely but
==3841967==  possible), you can try to increase the size of the
==3841967==  main thread stack using the --main-stacksize= flag.
==3841967==  The main thread stack size used in this run was 8388608.
==3841967== 
==3841967== HEAP SUMMARY:
==3841967==     in use at exit: 149,626 bytes in 1,143 blocks
==3841967==   total heap usage: 211,782 allocs, 210,639 frees, 90,582,963 bytes allocated
==3841967== 
==3841967== LEAK SUMMARY:
==3841967==    definitely lost: 0 bytes in 0 blocks
==3841967==    indirectly lost: 0 bytes in 0 blocks
==3841967==      possibly lost: 1,352 bytes in 18 blocks
==3841967==    still reachable: 148,274 bytes in 1,125 blocks
==3841967==                       of which reachable via heuristic:
==3841967==                         newarray           : 1,536 bytes in 16 blocks
==3841967==         suppressed: 0 bytes in 0 blocks
==3841967== Rerun with --leak-check=full to see details of leaked memory
==3841967== 
==3841967== For lists of detected and suppressed errors, rerun with: -s
==3841967== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

你可以把它克隆到机器上,

代码语言:javascript
复制
git clone https://github.com/randombit/botan.git

然后按照他们的官方网站的说明来构建和安装它。

您将需要创建一个用于应用程序的根证书颁发机构,为此您必须在您的计算机上安装OpenSSL。

在其中创建一个名为testApplicationcd的文件夹。

然后使用Bash,发出以下一系列命令来创建根CA,

代码语言:javascript
复制
# Generate private key
openssl genrsa -des3 -out myCA.key 2048
# Generate root certificate
openssl req -x509 -new -nodes -key myCA.key -sha256 -days 825 -out myCA.pem
# Convert to Botan Format
openssl pkcs8 -topk8 -in myCA.key > myCAKey.pkcs8.pem

请使用thisispassword作为密码。

在您的机器上安装clang编译器,然后您可以按以下方式编译源文件,

代码语言:javascript
复制
clang++ example.cpp -o example  -Wthread-safety -Wall -Wextra -g -std=c++17 -pthread -lssl -lcrypto -lbotan-2 --I/usr/include/botan-2

example.cpp

代码语言:javascript
复制
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <botan/tls_server.h>
#include <botan/tls_callbacks.h>
#include <botan/tls_session_manager.h>
#include <botan/tls_policy.h>
#include <botan/auto_rng.h>
#include <botan/certstor.h>
#include <botan/pk_keys.h>
#include <botan/pkcs10.h>
#include <botan/pkcs8.h>
#include <botan/x509self.h>
#include <botan/x509path.h>
#include <botan/x509_ca.h>
#include <botan/x509_ext.h>
#include <botan/pk_algs.h>
#include <botan/ber_dec.h>
#include <botan/der_enc.h>
#include <botan/oids.h>
#include <botan/rsa.h>

namespace TLS
{
    typedef std::chrono::duration<int, std::ratio<31556926>> years;

    class credentials : public Botan::Credentials_Manager
    {
    private:
        struct certificate
        {
            std::vector<Botan::X509_Certificate> certs;
            std::shared_ptr<Botan::Private_Key> key;
        };

        std::vector<certificate> creds;
        std::vector<std::shared_ptr<Botan::Certificate_Store>> store;

    public:
        void createCert(std::string hostname)
        {
            /**
             * Initialize Root CA
            **/

            Botan::AutoSeeded_RNG rng;

            const Botan::X509_Certificate rootCert("myCA.pem");

            std::ifstream rootCertPrivateKeyFile("myCAKey.pkcs8.pem");

            Botan::DataSource_Stream rootCertPrivateKeyStream(rootCertPrivateKeyFile);

            std::unique_ptr<Botan::Private_Key> rootCertPrivateKey = Botan::PKCS8::load_key(rootCertPrivateKeyStream, "thisispassword");

            Botan::X509_CA rootCA(rootCert, *rootCertPrivateKey, "SHA-256", rng);

            /**
            * Generate a Cert & Sign with Root CA
            **/

            Botan::X509_Cert_Options opts;
            std::shared_ptr<Botan::Private_Key> serverPrivateKeyShared(new Botan::RSA_PrivateKey(rng, 4096));
            Botan::RSA_PrivateKey* serverPrivateKey = (Botan::RSA_PrivateKey*)serverPrivateKeyShared.get();

            opts.common_name = hostname;
            opts.country = "US";

            auto now = std::chrono::system_clock::now();

            Botan::X509_Time todayDate(now);
            Botan::X509_Time expireDate(now + years(1));

            Botan::PKCS10_Request req = Botan::X509::create_cert_req(opts, *serverPrivateKey, "SHA-256", rng);

            auto serverCert = rootCA.sign_request(req, rng, todayDate, expireDate);

            /**
             * Load Cert to In-Memory Database
            **/

            certificate cert;

            cert.certs.push_back(serverCert);
            cert.key = serverPrivateKeyShared;

            creds.push_back(cert);
        }
    };
}; // namespace TLS

TLS::credentials globalCreds;

int main() {
    globalCreds.createCert("www.google.com");

    std::cout << "End" << "\n";

    return 0;
}

这是来自博坦利卜的函数,瓦伦是指,

代码语言:javascript
复制
void deallocate_memory(void* p, size_t elems, size_t elem_size)
   {
   if(p == nullptr)
      return;

   secure_scrub_memory(p, elems * elem_size);

#if defined(BOTAN_HAS_LOCKING_ALLOCATOR)
   if(mlock_allocator::instance().deallocate(p, elems, elem_size))
      return;
#endif

   std::free(p);
   }
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2021-02-08 23:23:12

“博坦”的作者回答说

问题在于全局定义的对象。

问题是,mlock池是在第一次使用时创建的,然后在主返回之后的某个时候销毁。首先,创建对象。它分配内存。这将导致创建池。毁灭是自毁的。所以首先泳池被毁了。然后,您的对象被销毁,并试图触摸内存(使其为零),它已经被取消了映射。

解决办法,

  • 创建一个Botan::Allocator_Initializer对象,以便在创建对象之前强制初始化(因此池一直存在直到您的对象被销毁后)
  • 禁用locking_allocator模块
  • 将env var BOTAN_MLOCK_POOL_SIZE设置为0
  • 没有全局vars

原则上,锁定分配器(而不是发送内存)只是对内存进行零化,并让操作系统在进程退出时不对其进行映射。这仍然可能打破不变量,但没有那么糟糕。它也会引起泄密,这是令人讨厌的。

我想因为它是直接被mmap编辑的而不是通过malloc的,所以没能追踪到它。

票数 41
EN

Stack Overflow用户

发布于 2021-02-11 02:44:30

全局变量,特别是单变量,是多线程复杂应用程序的祸患。在这种设计中,你总会遇到这样的问题。

我通常是这样做的:在main中,所有全局变量都被定义为局部变量,或者按照适当的顺序定义某个子函数,这样就会以适当的相反顺序销毁它。依赖注入类技术可以用于在“几乎所有”依赖于这些对象的情况下传递这些对象。我花了一些时间才意识到,在大型复杂应用程序中,这基本上是唯一可以调试的方法(想想看,应用程序本身和它在C++库之外使用的几十个库之间有2M的loc )。在全球从定制代码中删除,然后从几个有问题的库中删除后,“关闭死亡”的幽灵几乎消失了。我不能保证它能解决每个人的问题--因为人们可以很有创意地想出新的问题--但这是IMHO朝着正确方向迈出的一步。

票数 12
EN

Stack Overflow用户

发布于 2021-02-15 01:55:17

这是静态去初始化顺序“失败”的一个例子。

工艺学来防止这种情况,但是当您链接库时,它们可能无法工作,因为您无法控制它们的生命周期。

因此,最好的解决方案可能是在程序退出之前、在main的末尾或在atexit函数中显式清除globalCreds的内容。其次,如果不需要清理,最好是泄漏结构。

如何泄漏从异翻获取的示例

代码语言:javascript
复制
TLS::credentials& x() {
  static TLS::credentials* creds = new TLS::credentials();
  return *creds;
}
TLS::credentials &globalCreds = x();

是的,这也冒犯了我的整洁感。

但是这只是工作,globalCreds应该在main中创建,传递给需要它作为引用的类(在main中也是创建的,后面是Cred)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66068134

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档