diff --git a/lib/creds.c b/lib/creds.c index a11816ca54..b24b8af24c 100644 --- a/lib/creds.c +++ b/lib/creds.c @@ -46,6 +46,7 @@ CURLcode Curl_creds_create(const char *user, size_t salen = sasl_authzid ? strlen(sasl_authzid) : 0; size_t sslen = sasl_service ? strlen(sasl_service) : 0; char *s, *buf; + size_t bufsize; CURLcode result = CURLE_OK; Curl_creds_unlink(pcreds); @@ -64,13 +65,14 @@ CURLcode Curl_creds_create(const char *user, } /* null-terminator for user already part of struct */ - creds = curlx_calloc(1, sizeof(*creds) + - ulen + plen + 1 + olen + 1 + salen + 1 + sslen + 1); + bufsize = ulen + plen + 1 + olen + 1 + salen + 1 + sslen + 1; + creds = curlx_calloc(1, sizeof(*creds) + bufsize); if(!creds) { result = CURLE_OUT_OF_MEMORY; goto out; } + creds->bufsize = bufsize; creds->refcount = 1; creds->source = source; /* Some compilers try to be too smart about our dynamic struct size */ @@ -144,6 +146,7 @@ void Curl_creds_unlink(struct Curl_creds **pcreds) if(creds->refcount) creds->refcount--; if(!creds->refcount) { + curlx_memzero(creds, sizeof(*creds) + creds->bufsize); curlx_free(creds); } } diff --git a/lib/creds.h b/lib/creds.h index 36deff323e..8b14cad719 100644 --- a/lib/creds.h +++ b/lib/creds.h @@ -39,6 +39,7 @@ struct Curl_creds { const char *sasl_service; /* non-NULL, maybe empty string */ uint32_t refcount; uint8_t source; /* CREDS_* value */ + size_t bufsize; /* extra bytes added to sizeof(struct Curl_creds) */ char buf[1]; }; diff --git a/lib/curl_setup.h b/lib/curl_setup.h index 0bbf717c89..bcad79beb9 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -1338,20 +1338,6 @@ extern curl_calloc_callback Curl_ccalloc; (ptr) = NULL; \ } while(0) -/* Same as curlx_safefree() but zeroes memory before freeing */ -#define curlx_safefreezero(ptr, size) \ - do { \ - curlx_freezero(ptr, size); \ - (ptr) = NULL; \ - } while(0) - -/* Same as curlx_safefreezero() but determines length with strlen() */ -#define curlx_safefreezeroz(ptr) \ - do { \ - curlx_freezeroz(ptr); \ - (ptr) = NULL; \ - } while(0) - #include /* for CURL_EXTERN, curl_socket_t, mprintf.h */ #ifdef DEBUGBUILD @@ -1642,14 +1628,14 @@ typedef struct sockaddr_un { #if defined(_MSC_VER) && defined(NTDDI_VERSION) && \ (NTDDI_VERSION >= 0x0A000010) /* MS SDK 10.0.26100.0+ */ #pragma comment(lib, "volatileaccessu.lib") -#define curlx_memzero(buf, size) SecureZeroMemory2(buf, size) +#define curlx_memzero_low(buf, size) SecureZeroMemory2(buf, size) #else -#define curlx_memzero(buf, size) SecureZeroMemory(buf, size) +#define curlx_memzero_low(buf, size) SecureZeroMemory(buf, size) #endif #elif defined(HAVE_MEMSET_S) -#define curlx_memzero(buf, size) (void)memset_s(buf, size, 0, size) +#define curlx_memzero_low(buf, size) (void)memset_s(buf, size, 0, size) #elif defined(HAVE_MEMSET_EXPLICIT) -#define curlx_memzero(buf, size) (void)memset_explicit(buf, 0, size) +#define curlx_memzero_low(buf, size) (void)memset_explicit(buf, 0, size) #elif defined(__CYGWIN__) || \ (defined(__NEWLIB__) && !defined(__CLIB2__)) || \ (defined(__GLIBC__) && \ @@ -1657,17 +1643,29 @@ typedef struct sockaddr_un { (defined(__DragonFly__) && __DragonFly_version >= 500600 /* v5.6+ */) || \ (defined(__FreeBSD__) && __FreeBSD_version >= 1100037 /* v11.0+ */) || \ (defined(__OpenBSD__) && OpenBSD >= 201405 /* v5.5+ */) -#define curlx_memzero(buf, size) explicit_bzero(buf, size) +#define curlx_memzero_low(buf, size) explicit_bzero(buf, size) #elif defined(__NetBSD__) && __NetBSD_Version__ >= 702000000 /* v7.2+ */ -#define curlx_memzero(buf, size) (void)explicit_memset(buf, 0, size) +#define curlx_memzero_low(buf, size) (void)explicit_memset(buf, 0, size) #endif #endif /* !_CURL_LOCAL_MEMZERO */ -#ifndef curlx_memzero +#ifndef curlx_memzero_low #define USE_CURLX_MEMZERO -void curlx_memzero(void *buf, size_t size); +void curlx_memzero_low(void *buf, size_t size); #endif -void curlx_freezero(void *buf, size_t size); -void curlx_freezeroz(void *buf); + +/* Public macro with NULL-check */ +#define curlx_memzero(ptr, size) \ + do { \ + if(ptr) \ + curlx_memzero_low(ptr, size); \ + } while(0) + +/* Public macro with NULL-check for null-terminated strings */ +#define curlx_strzero(str) \ + do { \ + if(str) \ + curlx_memzero_low(str, strlen(str)); \ + } while(0) #endif /* HEADER_CURL_SETUP_H */ diff --git a/lib/curl_share.c b/lib/curl_share.c index 94469bc3ef..b7c331adf7 100644 --- a/lib/curl_share.c +++ b/lib/curl_share.c @@ -34,6 +34,9 @@ static void share_destroy(struct Curl_share *share) { + if(!share) + return; + if(share->specifier & (1 << CURL_LOCK_DATA_CONNECT)) { Curl_cpool_destroy(&share->cpool); } @@ -61,7 +64,7 @@ static void share_destroy(struct Curl_share *share) #ifdef USE_MUTEX Curl_mutex_destroy(&share->lock); #endif - share->magic = 0; + curlx_memzero(share, sizeof(*share)); curlx_free(share); } diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c index 3ea17621b1..c733892d86 100644 --- a/lib/curl_sspi.c +++ b/lib/curl_sspi.c @@ -100,6 +100,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, xcharp_u domain, dup_domain; xcharp_u passwd, dup_passwd; size_t domlen = 0; + size_t pwlen; domain.const_tchar_ptr = TEXT(""); @@ -155,17 +156,20 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, curlx_free(dup_domain.tchar_ptr); return CURLE_OUT_OF_MEMORY; } + pwlen = _tcslen(passwd.tchar_ptr); dup_passwd.tchar_ptr = curlx_tcsdup(passwd.tchar_ptr); if(!dup_passwd.tchar_ptr) { curlx_free(dup_user.tchar_ptr); curlx_free(dup_domain.tchar_ptr); + curlx_memzero(passwd.tchar_ptr, pwlen * sizeof(*passwd.tchar_ptr)); curlx_free(passwd.tchar_ptr); return CURLE_OUT_OF_MEMORY; } identity->Password = dup_passwd.tbyte_ptr; - identity->PasswordLength = curlx_uztoul(_tcslen(dup_passwd.tchar_ptr)); + identity->PasswordLength = curlx_uztoul(pwlen); dup_passwd.tchar_ptr = NULL; + curlx_memzero(passwd.tchar_ptr, pwlen * sizeof(*passwd.tchar_ptr)); curlx_free(passwd.tchar_ptr); identity->User = dup_user.tbyte_ptr; @@ -199,6 +203,8 @@ void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity) { if(identity) { curlx_safefree(identity->User); + curlx_memzero(identity->Password, + identity->PasswordLength * sizeof(*identity->Password)); curlx_safefree(identity->Password); curlx_safefree(identity->Domain); } diff --git a/lib/curlx/strdup.c b/lib/curlx/strdup.c index 8e788ea34c..c4dd8f969d 100644 --- a/lib/curlx/strdup.c +++ b/lib/curlx/strdup.c @@ -101,25 +101,9 @@ static void *(* const volatile p_curlx_memset)(void *buf, int val, /* Local fallback in case there is no system function to securely zero a memory buffer. */ -void curlx_memzero(void *buf, size_t size) +void curlx_memzero_low(void *buf, size_t size) { if(buf) p_curlx_memset(buf, 0, size); } #endif - -/* Free 'buf' after zeroing its content. */ -void curlx_freezero(void *buf, size_t size) -{ - if(buf) - curlx_memzero(buf, size); - curlx_free(buf); -} - -/* Free 'buf' after zeroing its content, where 'buf' is null-terminated. */ -void curlx_freezeroz(void *buf) -{ - if(buf) - curlx_memzero(buf, strlen(buf)); - curlx_free(buf); -} diff --git a/lib/imap.c b/lib/imap.c index fc3077985d..5c1229193b 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -613,6 +613,7 @@ static CURLcode imap_perform_login(struct Curl_easy *data, passwd ? passwd : ""); curlx_free(user); + curlx_strzero(passwd); curlx_free(passwd); if(!result) diff --git a/lib/mqtt.c b/lib/mqtt.c index 8482477b97..87b94c0f75 100644 --- a/lib/mqtt.c +++ b/lib/mqtt.c @@ -347,8 +347,10 @@ static CURLcode mqtt_connect(struct Curl_easy *data) result = mqtt_send(data, packet, packetlen); end: - if(packet) + if(packet) { + curlx_memzero(packet, packetlen); curlx_free(packet); + } Curl_creds_unlink(&data->state.creds); return result; } diff --git a/lib/multi.c b/lib/multi.c index d0fa68ab4c..772116e9f5 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -3043,6 +3043,7 @@ CURLMcode curl_multi_cleanup(CURLM *m) Curl_uint32_bset_destroy(&multi->pending); Curl_uint32_bset_destroy(&multi->msgsent); Curl_uint32_tbl_destroy(&multi->xfers); + curlx_memzero(multi, sizeof(*multi)); curlx_free(multi); return CURLM_OK; diff --git a/lib/setopt.c b/lib/setopt.c index e2e30622f1..6e366456c0 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -154,6 +154,7 @@ static CURLcode setstropt_userpwd(const char *option, char **userp, curlx_free(*userp); *userp = user; + curlx_strzero(*passwdp); curlx_free(*passwdp); *passwdp = passwd; @@ -1657,6 +1658,7 @@ static CURLcode setopt_cptr_proxy(struct Curl_easy *data, CURLoption option, result = Curl_urldecode(p, 0, &s->str[STRING_PROXYPASSWORD], NULL, REJECT_ZERO); curlx_free(u); + curlx_strzero(p); curlx_free(p); break; } diff --git a/lib/url.c b/lib/url.c index 8da2aca924..0ce9639c0e 100644 --- a/lib/url.c +++ b/lib/url.c @@ -153,6 +153,15 @@ void Curl_freeset(struct Curl_easy *data) enum dupblob j; for(i = (enum dupstring)0; i < STRING_LAST; i++) { + if(i == STRING_PASSWORD || + i == STRING_KEY_PASSWD || +#ifndef CURL_DISABLE_PROXY + i == STRING_PROXYPASSWORD || + i == STRING_KEY_PASSWD_PROXY || +#endif + i == STRING_BEARER) { + curlx_strzero(data->set.str[i]); + } curlx_safefree(data->set.str[i]); } @@ -306,6 +315,7 @@ CURLcode Curl_close(struct Curl_easy **datap) #ifndef CURL_DISABLE_PROXY Curl_ssl_config_cleanup(&data->set.proxy_ssl.primary); #endif + curlx_memzero(data, sizeof(*data)); curlx_free(data); return CURLE_OK; } diff --git a/lib/urlapi.c b/lib/urlapi.c index 7a926debb6..1739b21bcc 100644 --- a/lib/urlapi.c +++ b/lib/urlapi.c @@ -69,6 +69,7 @@ static void free_urlhandle(struct Curl_URL *u) { curlx_free(u->scheme); curlx_free(u->user); + curlx_strzero(u->password); curlx_free(u->password); curlx_free(u->options); curlx_free(u->host); @@ -322,6 +323,7 @@ UNITTEST CURLUcode parse_hostname_login(struct Curl_URL *u, } if(passwdp) { + curlx_strzero(u->password); curlx_free(u->password); u->password = passwdp; } @@ -338,6 +340,7 @@ UNITTEST CURLUcode parse_hostname_login(struct Curl_URL *u, out: curlx_free(userp); + curlx_strzero(passwdp); curlx_free(passwdp); curlx_free(optionsp); curlx_safefree(u->user); @@ -1783,6 +1786,7 @@ static CURLUcode urlset_clear(CURLU *u, CURLUPart what) curlx_safefree(u->user); break; case CURLUPART_PASSWORD: + curlx_strzero(u->password); curlx_safefree(u->password); break; case CURLUPART_OPTIONS: @@ -2029,6 +2033,8 @@ nomem: } } + if(what == CURLUPART_PASSWORD) + curlx_strzero(*storep); curlx_free(*storep); *storep = (char *)CURL_UNCONST(newp); } diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c index 3feb3e7824..ab9373b240 100644 --- a/src/tool_cfgable.c +++ b/src/tool_cfgable.c @@ -145,7 +145,9 @@ static void free_config_fields(struct OperationConfig *config) curlx_safefree(config->proxy_key); curlx_safefree(config->key_type); curlx_safefree(config->proxy_key_type); + curlx_strzero(config->key_passwd); curlx_safefree(config->key_passwd); + curlx_strzero(config->proxy_key_passwd); curlx_safefree(config->proxy_key_passwd); curlx_safefree(config->pubkey); curlx_safefree(config->hostpubmd5); @@ -158,6 +160,7 @@ static void free_config_fields(struct OperationConfig *config) curlx_safefree(config->request_target); curlx_safefree(config->customrequest); curlx_safefree(config->krblevel); + curlx_strzero(config->oauth_bearer); curlx_safefree(config->oauth_bearer); curlx_safefree(config->sasl_authzid); curlx_safefree(config->unix_socket_path);