在OpenSSL的功能EVP_EncryptFinal_ex内存泄漏 [英] Memory leak in OpenSSL function EVP_EncryptFinal_ex
问题描述
我实现了基于教程加密过程:
http://www.openssl.org/docs/crypto/EVP_EncryptInit.html #
当我运行它低谷valgring,得到了以下报告:
== == 2371 176 1块字节仍处于负的战绩3可达6
== == 2371在0x4C2B6CD:的malloc(在/ usr / lib中/的valgrind / VG preload_memcheck-amd64- linux.so)
== == 2371通过0x56CA133:CRYPTO_malloc(以/lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
== == 2371通过0x575280F:lh_new(以/lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
== == 2371通过0x5754D4F:??? (在/lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
== == 2371通过0x575503E:??? (在/lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
== == 2371通过0x5755A1D:ERR_get_state(以/lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
== == 2371通过0x5755E5E:ERR_put_error(以/lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
== == 2371通过0x5757E38:EVP_DecryptFinal_ex(以/lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
== == 2371通过0x46DA2A:unmangleUrl(标准::字符串常量和放大器;,标准::字符串常量和放大器;,标准::字符串常量和放大器;)(mangle_url.cpp:84)
== == 2371通过0x46621C:主(main.cpp中:348)
我下载了OpenSSL源$ C $ C。里面ERR_put_error我看到ERR_get_state内存分配了,里面err_clear_data释放内存,但累积里面err_clear_data的逻辑。它得到了释放只有标志ERR_TXT_MALLOCED,我没有看到谁在升旗。
我在做什么错了?
我使用Ubuntu 12.04
$猫的/ etc /问题
Ubuntu的LTS 12.04.2 \\ n \\升
和OpenSSL的版本是
$ OpenSSL的版本
OpenSSL的1.0.1 2012年3月14日
我的code段mangle_url.cpp:
的std ::字符串unmangleUrl(常量标准::字符串&放大器;键,常量标准::字符串&放大器;四,常量标准::字符串&安培; URL)
{
标准::字符串binUrl = hexToBin(URL);
标准::字符串资源;
res.resize(binUrl.size()* 2);
EVP_CIPHER_CTX CTX;
EVP_CIPHER_CTX_init(安培; CTX);
EVP_DecryptInit_ex(安培; CTX,EVP_bf_cbc(),NULL,(const的无符号字符*)及键[0],(const的无符号字符*)及IV [0]);
INT LEN;
如果(EVP_DecryptUpdate(安培;!CTX(无符号字符*)及资源[0],和放大器; LEN(const的无符号字符*)及binUrl [0],binUrl.size()))
{
EVP_CIPHER_CTX_cleanup(安培; CTX);
抛出std :: runtime_error(无法解密URL);
}
INT tmpLen;
如果(EVP_DecryptFinal_ex(安培;!CTX(无符号字符*)及资源[LEN],&安培; tmpLen))
{
EVP_CIPHER_CTX_cleanup(安培; CTX);
抛出std :: runtime_error(无法解密URL);
}
LEN + = tmpLen;
EVP_CIPHER_CTX_cleanup(安培; CTX);
res.resize(LEN); 返回水库;
}
从OpenSSL的err.c中code:
...
无效ERR_put_error(INT lib下,INT FUNC,诠释原因,为const char *文件,
INT线)
{
ERR_STATE * ES;#IFDEF _OSD_POSIX
/ *在BS2000-OSD POSIX子系统,编译器生成
*形式的路径名* POSIX(/ etc / passwd文件)。
*这个肮脏的黑客他们去掉的东西明智的。
* @@@我们不应该修改常量字符串,虽然。
* /
如果(STRNCMP(文件,* POSIX(,sizeof的(* POSIX() - 1)== 0){
字符*结束; / *跳过* POSIX(preFIX * /
文件+ = sizeof的(* POSIX() - 1;
最终=安培;文件[strlen的(文件)-1];
如果(*年底==')')
*结束='\\ 0';
/ *可选:仅使用路径的基本名称。 * /
如果((完= strrchr(文件,/))!= NULL)
文件=安培;结束[1];
}
#万一
ES = ERR_get_state(); < - 内存分配得到 ES-GT&;顶=(ES>顶+ 1)%ERR_NUM_ERRORS;
如果(ES>顶== ES-GT&;底部)
ES-GT&;底部=(ES>底部+ 1)%ERR_NUM_ERRORS;
ES-GT&; err_flags [第ES>顶] = 0;
ES-GT&; err_buffer [第ES>顶] = ERR_PACK(LIB,FUNC,原因);
ES-GT&; err_file [第ES>顶] =文件;
ES-GT&; err_line [第ES>顶] =线;
err_clear_data(ES,ES-GT&;顶部); < - 假设被释放
}
...
ERR_STATE * ERR_get_state(无效)
{
静态ERR_STATE备用;
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 ==错误状态,如果为null,使一个新的* /
如果(RET == NULL)
{
RET =(ERR_STATE *)OPENSSL_malloc(的sizeof(ERR_STATE)); < - 内存分配得到
如果(RET == NULL)回报率(安培;回退);
CRYPTO_THREADID_cpy(安培; ret-> TID,&安培; TID);
ret->顶= 0;
ret->底部= 0;
对于(i = 0; I< ERR_NUM_ERRORS;我++)
{
ret-> err_data [我] = NULL;
ret-> err_data_flags [I] = 0;
}
TMPP = ERRFN(thread_set_item)(RET);
/ *要检查是否插入失败,做一个GET。 * /
如果(ERRFN(thread_get_item)(RET)!= RET)
{
ERR_STATE_free(RET); / *无法将其插入* /
返回(安培;回退);
}
/ *如果比赛在这个函数中发生,我们来到第二,磷酸川芎嗪
*是我们刚刚更换了第一个。 * /
如果(TMPP)
ERR_STATE_free(TMPP);
}
返回RET;
}
...
的#define err_clear_data(P,I)\\
做{\\
如果(((对) - > err_data [I] = NULL)及&放大器; \\!
(对) - > err_data_flags [1] - 放大器; ERR_TXT_MALLOCED)\\< - 与ERR_TXT_MALLOCED标志weired逻辑
{\\
OPENSSL_free((对) - > err_data [I]); \\
(对) - > err_data [I] = NULL; \\
} \\
(对) - > err_data_flags [I] = 0; \\
}而(0)
呼叫退出程序前这些功能,你应该罚款:
CRYPTO_cleanup_all_ex_data();
ERR_free_strings();
ERR_remove_state(0);
EVP_cleanup();
I implemented encryption procedure based on the tutorial:
http://www.openssl.org/docs/crypto/EVP_EncryptInit.html#
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)
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.
What I am doing wrong?
I am using Ubuntu 12.04
$ cat /etc/issue
Ubuntu 12.04.2 LTS \n \l
And OpenSSL version is
$ openssl version
OpenSSL 1.0.1 14 Mar 2012
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;
}
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 = '\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)
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屋!