OpenSSL 函数 EVP_EncryptFinal_ex 中的内存泄漏 [英] Memory leak in OpenSSL function EVP_EncryptFinal_ex

查看:24
本文介绍了OpenSSL 函数 EVP_EncryptFinal_ex 中的内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I implemented encryption procedure based on the tutorial:

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

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

When I run it trough valgring and got the following report:

==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 时它才会被释放,我看不到是谁在举起标志.

I downloaded source code of OpenSSL. Inside ERR_put_error I see memory allocation in ERR_get_state, and releasing memory inside err_clear_data, but accruing the logic inside err_clear_data. It got release only if flag ERR_TXT_MALLOCED, and I do not see who is raising the flag.

我做错了什么?

我使用的是 Ubuntu 12.04

I am using Ubuntu 12.04

$ cat /etc/issue
Ubuntu 12.04.2 LTS 
 l

OpenSSL 版本是

And OpenSSL version is

$ openssl version
OpenSSL 1.0.1 14 Mar 2012

我的代码片段 mangle_url.cpp:

My code snippet 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 的代码:

Code from 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 = '';
        /* 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)

推荐答案

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

Call these functions before exiting your program, you should be fine:

CRYPTO_cleanup_all_ex_data();
ERR_free_strings();
ERR_remove_state(0);
EVP_cleanup();

这篇关于OpenSSL 函数 EVP_EncryptFinal_ex 中的内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆