打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
OpenSSL函数EVP_EncryptFinal_ex中的内存泄漏

我根据教程实现了加密程序:

http://www.openssl.org/docs/crypto/EVP_EncryptInit.html#

当我通过valgring运行它并得到以下报告:

==2371== 176 bytes in 1 blocks are still reachable in loss record 3 of 6==2371==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64- linux.so)==2371==    by 0x56CA133: CRYPTO_malloc (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)==2371==    by 0x575280F: lh_new (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)==2371==    by 0x5754D4F: ??? (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)==2371==    by 0x575503E: ??? (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)==2371==    by 0x5755A1D: ERR_get_state (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)==2371==    by 0x5755E5E: ERR_put_error (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)==2371==    by 0x5757E38: EVP_DecryptFinal_ex (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)==2371==    by 0x46DA2A: unmangleUrl(std::string const&, std::string const&, std::string const&) (mangle_url.cpp:84)==2371==    by 0x46621C: main (main.cpp:348)

我下载了OpenSSL的源代码.在ERR_put_error里面,我看到ERR_get_state中的内存分配,并在err_clear_data中释放内存,但在err_clear_data中产生了逻辑.它只有在标志ERR_TXT_MALLOCED时才会释放,而我看不到谁在举旗.

我做错了什么?

我使用的是Ubuntu 12.04

$cat /etc/issueUbuntu 12.04.2 LTS \n \l

而OpenSSL版本则是

$openssl versionOpenSSL 1.0.1 14 Mar 2012

我的代码片段mangle_url.cpp:

std::string unmangleUrl(const std::string &key, const std::string &iv, const std::string &url){    std::string binUrl = hexToBin(url);    std::string res;    res.resize(binUrl.size() * 2);    EVP_CIPHER_CTX ctx;    EVP_CIPHER_CTX_init(&ctx);    EVP_DecryptInit_ex(&ctx, EVP_bf_cbc(), NULL, (const unsigned char *)&key[0], (const unsigned char *)&iv[0]);    int len;    if(!EVP_DecryptUpdate(&ctx, (unsigned char *)&res[0], &len, (const unsigned char *)&binUrl[0], binUrl.size()))    {        EVP_CIPHER_CTX_cleanup(&ctx);        throw std::runtime_error("cannot decrypt URL");    }    int tmpLen;    if(!EVP_DecryptFinal_ex(&ctx, (unsigned char *)&res[len], &tmpLen))    {        EVP_CIPHER_CTX_cleanup(&ctx);        throw std::runtime_error("cannot decrypt URL");    }    len  = tmpLen;    EVP_CIPHER_CTX_cleanup(&ctx);    res.resize(len);    return res;}

OpenSSL err.c中的代码:

void ERR_put_error(int lib, int func, int reason, const char *file,         int line)    {    ERR_STATE *es;#ifdef _OSD_POSIX    /* In the BS2000-OSD POSIX subsystem, the compiler generates     * path names in the form "*POSIX(/etc/passwd)".     * This dirty hack strips them to something sensible.     * @@@ We shouldn't modify a const string, though.     */    if (strncmp(file,"*POSIX(", sizeof("*POSIX(")-1) == 0) {        char *end;        /* Skip the "*POSIX(" prefix */        file  = sizeof("*POSIX(")-1;        end = &file[strlen(file)-1];        if (*end == ')')            *end = '\0';        /* Optional: use the basename of the path only. */        if ((end = strrchr(file, '/')) != NULL)            file = &end[1];    }#endif    es=ERR_get_state(); <-- memory got allocated    es->top=(es->top 1)%ERR_NUM_ERRORS;    if (es->top == es->bottom)        es->bottom=(es->bottom 1)%ERR_NUM_ERRORS;    es->err_flags[es->top]=0;    es->err_buffer[es->top]=ERR_PACK(lib,func,reason);    es->err_file[es->top]=file;    es->err_line[es->top]=line;    err_clear_data(es,es->top); <-- suppose to be released     }

ERR_STATE *ERR_get_state(void)    {    static ERR_STATE fallback;    ERR_STATE *ret,tmp,*tmpp=NULL;    int i;    CRYPTO_THREADID tid;    err_fns_check();    CRYPTO_THREADID_current(&tid);    CRYPTO_THREADID_cpy(&tmp.tid, &tid);    ret=ERRFN(thread_get_item)(&tmp);    /* ret == the error state, if NULL, make a new one */    if (ret == NULL)        {        ret=(ERR_STATE *)OPENSSL_malloc(sizeof(ERR_STATE)); <-- memory got allocated        if (ret == NULL) return(&fallback);        CRYPTO_THREADID_cpy(&ret->tid, &tid);        ret->top=0;        ret->bottom=0;        for (i=0; i<ERR_NUM_ERRORS; i  )            {            ret->err_data[i]=NULL;            ret->err_data_flags[i]=0;            }        tmpp = ERRFN(thread_set_item)(ret);        /* To check if insertion failed, do a get. */        if (ERRFN(thread_get_item)(ret) != ret)            {            ERR_STATE_free(ret); /* could not insert it */            return(&fallback);            }        /* If a race occured in this function and we came second, tmpp         * is the first one that we just replaced. */        if (tmpp)            ERR_STATE_free(tmpp);        }    return ret;    }

#define err_clear_data(p,i)     do {     if (((p)->err_data[i] != NULL) &&         (p)->err_data_flags[i] & ERR_TXT_MALLOCED) \ <-- weired logic with ERR_TXT_MALLOCED flag        {          OPENSSL_free((p)->err_data[i]);         (p)->err_data[i]=NULL;         }     (p)->err_data_flags[i]=0;     } while(0)

解决方法:

在退出程序之前调用这些函数,你应该没问题:

CRYPTO_cleanup_all_ex_data();ERR_free_strings();ERR_remove_state(0);EVP_cleanup();
来源:http://www.icode9.com/content-3-244101.html
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
SSL连接建立过程分析(1)
网络安全编程与实践(第6章 OpenSSLEVP编程 代码)
openssl学习之ccm,gcm 模式
用OpenSSL编写SSL,TLS程序
ffmpeg超详细综合教程(二)
《源码探秘 CPython》83. 激活 Python 虚拟机
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服