Memory leak in OpenSSL function EVP_EncryptFinal_ex

I applied a textbook based encryption procedure:

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

When I ran it through valgring and received 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 the OpenSSL source code. Inside ERR_put_error, I see memory allocation in ERR_get_state and freeing memory inside err_clear_data, but the logic inside err_clear_data is growing. He only got an exemption if the flag is ERR_TXT_MALLOCED, and I don’t see who raises the flag.

What am I doing wrong?

I am using Ubuntu 12.04

 $ cat /etc/issue Ubuntu 12.04.2 LTS \n \l 

And the version of OpenSSL

 $ openssl version OpenSSL 1.0.1 14 Mar 2012 

My code snippet is 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) 
+4
source share
1 answer

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

 CRYPTO_cleanup_all_ex_data(); ERR_free_strings(); ERR_remove_state(0); EVP_cleanup(); 
+7
source

Source: https://habr.com/ru/post/1499543/


All Articles