更新 当
TLS::credentials creds在全局范围内声明时,我发现了这种情况,但是如果我在seg之外声明它,那么seg故障就不会发生。 我需要它是全局的,因为它有助于缓存证书,并且多个线程可以使用其他线程创建的证书,而无需花费时间创建新的证书。 X进一步减少了代码,从200行左右。转到100行
我使用Botan创建了一个TLS应用程序,我的应用程序在应用程序的末尾出现了一个seg故障。
我试着用Val差尔调试它,但是它没有结果。
这是瓦伦的堆栈追踪,
==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)你可以把它克隆到机器上,
git clone https://github.com/randombit/botan.git然后按照他们的官方网站的说明来构建和安装它。
您将需要创建一个用于应用程序的根证书颁发机构,为此您必须在您的计算机上安装OpenSSL。
在其中创建一个名为testApplication和cd的文件夹。
然后使用Bash,发出以下一系列命令来创建根CA,
# 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编译器,然后您可以按以下方式编译源文件,
clang++ example.cpp -o example -Wthread-safety -Wall -Wextra -g -std=c++17 -pthread -lssl -lcrypto -lbotan-2 --I/usr/include/botan-2example.cpp
#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;
}这是来自博坦利卜的函数,瓦伦是指,
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);
}发布于 2021-02-08 23:23:12
“博坦”的作者回答说
问题在于全局定义的对象。
问题是,mlock池是在第一次使用时创建的,然后在主返回之后的某个时候销毁。首先,创建对象。它分配内存。这将导致创建池。毁灭是自毁的。所以首先泳池被毁了。然后,您的对象被销毁,并试图触摸内存(使其为零),它已经被取消了映射。
解决办法,
原则上,锁定分配器(而不是发送内存)只是对内存进行零化,并让操作系统在进程退出时不对其进行映射。这仍然可能打破不变量,但没有那么糟糕。它也会引起泄密,这是令人讨厌的。
我想因为它是直接被mmap编辑的而不是通过malloc的,所以没能追踪到它。
发布于 2021-02-11 02:44:30
全局变量,特别是单变量,是多线程复杂应用程序的祸患。在这种设计中,你总会遇到这样的问题。
我通常是这样做的:在main中,所有全局变量都被定义为局部变量,或者按照适当的顺序定义某个子函数,这样就会以适当的相反顺序销毁它。依赖注入类技术可以用于在“几乎所有”依赖于这些对象的情况下传递这些对象。我花了一些时间才意识到,在大型复杂应用程序中,这基本上是唯一可以调试的方法(想想看,应用程序本身和它在C++库之外使用的几十个库之间有2M的loc )。在全球从定制代码中删除,然后从几个有问题的库中删除后,“关闭死亡”的幽灵几乎消失了。我不能保证它能解决每个人的问题--因为人们可以很有创意地想出新的问题--但这是IMHO朝着正确方向迈出的一步。
发布于 2021-02-15 01:55:17
这是静态去初始化顺序“失败”的一个例子。
有工艺学来防止这种情况,但是当您链接库时,它们可能无法工作,因为您无法控制它们的生命周期。
因此,最好的解决方案可能是在程序退出之前、在main的末尾或在atexit函数中显式清除globalCreds的内容。其次,如果不需要清理,最好是泄漏结构。
如何泄漏从异翻获取的示例
TLS::credentials& x() {
static TLS::credentials* creds = new TLS::credentials();
return *creds;
}
TLS::credentials &globalCreds = x();是的,这也冒犯了我的整洁感。
但是这只是工作,globalCreds应该在main中创建,传递给需要它作为引用的类(在main中也是创建的,后面是Cred)。
https://stackoverflow.com/questions/66068134
复制相似问题