From 8d3c4fe344d982c052917f20084c14001c3b9156 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Fri, 12 Jun 2026 14:37:55 +0200 Subject: [PATCH] sspi: free libcurl allocated memory with curlx_free DecryptMessage() decrypts the buffer in place, overwriting the original contents. It does not allocate any new buffer so the single original buffer should be freed using the same memory "system" that allocated it. Reported-by: Trail of Bits Closes #21990 --- lib/socks_sspi.c | 29 ++++++++++++----------------- lib/vauth/krb5_sspi.c | 8 ++++---- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index 7c043093e1..8ab538fba1 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -421,8 +421,7 @@ static CURLcode socks5_sspi_encrypt(struct Curl_cfilter *cf, if(result || (actualread != us_length)) { failf(data, "Failed to receive SSPI encryption type."); - curlx_free(sspi_w_token[0].pvBuffer); - return result ? result : CURLE_COULDNT_CONNECT; + goto fail; } if(!data->set.socks5_gssapi_nec) { @@ -432,34 +431,26 @@ static CURLcode socks5_sspi_encrypt(struct Curl_cfilter *cf, sspi_w_token[1].cbBuffer = 0; sspi_w_token[1].pvBuffer = NULL; - status = Curl_pSecFn->DecryptMessage(sspi_context, &wrap_desc, - 0, &qop); + /* At least one of the descriptors must be of type SECBUFFER_DATA. The + message is decrypted in place so the SECBUFFER_DATA receives a pointer + to the message in SECBUFFER_STREAM. */ + status = Curl_pSecFn->DecryptMessage(sspi_context, &wrap_desc, 0, &qop); - if(check_sspi_err(data, status, "DecryptMessage")) { - if(sspi_w_token[1].pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); - curlx_free(sspi_w_token[0].pvBuffer); - return CURLE_COULDNT_CONNECT; - } + if(check_sspi_err(data, status, "DecryptMessage")) + goto fail; if(sspi_w_token[1].cbBuffer != 1) { failf(data, "Invalid SSPI encryption response length (%lu).", (unsigned long)sspi_w_token[1].cbBuffer); - if(sspi_w_token[1].pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); - curlx_free(sspi_w_token[0].pvBuffer); - return CURLE_COULDNT_CONNECT; } memcpy(socksreq, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); - Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); } else { if(sspi_w_token[0].cbBuffer != 1) { failf(data, "Invalid SSPI encryption response length (%lu).", (unsigned long)sspi_w_token[0].cbBuffer); - curlx_free(sspi_w_token[0].pvBuffer); - return CURLE_COULDNT_CONNECT; + goto fail; } memcpy(socksreq, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); } @@ -471,6 +462,10 @@ static CURLcode socks5_sspi_encrypt(struct Curl_cfilter *cf, " GSS-API confidentiality")); return CURLE_OK; + +fail: + curlx_free(sspi_w_token[0].pvBuffer); + return CURLE_COULDNT_CONNECT; } CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, diff --git a/lib/vauth/krb5_sspi.c b/lib/vauth/krb5_sspi.c index de1dc58539..dd03a6c64c 100644 --- a/lib/vauth/krb5_sspi.c +++ b/lib/vauth/krb5_sspi.c @@ -291,7 +291,10 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, input_buf[1].pvBuffer = NULL; input_buf[1].cbBuffer = 0; - /* Decrypt the inbound challenge and obtain the qop */ + /* Decrypt the inbound challenge and obtain the qop. The encrypted message + is decrypted in place, overwriting the original contents of its buffer. + The SECBUFFER_DATA receives a pointer to the message in + SECBUFFER_STREAM. */ status = Curl_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop); if(status != SEC_E_OK) { infof(data, "GSSAPI handshake failure (empty security message)"); @@ -310,9 +313,6 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, max_size = ((unsigned long)indata[1] << 16) | ((unsigned long)indata[2] << 8) | indata[3]; - /* Free the challenge as it is not required anymore */ - Curl_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer); - /* Process the security layer */ if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) { infof(data, "GSSAPI handshake failure (invalid security layer)");