v3-0001-libpq-Make-SSL-certificate-callback-in-backend-th.patch
application/octet-stream
Filename: v3-0001-libpq-Make-SSL-certificate-callback-in-backend-th.patch
Type: application/octet-stream
Part: 0
Message:
Re: libpq OpenSSL and multithreading
Patch
Format: format-patch
Series: patch v3-0001
Subject: libpq: Make SSL certificate callback in backend threadsafe
| File | + | − |
|---|---|---|
| src/backend/libpq/be-secure-openssl.c | 26 | 5 |
From 73abaa13690e54875c4b1a4ca7c85bc181df6db8 Mon Sep 17 00:00:00 2001
From: Daniel Gustafsson <dgustafsson@postgresql.org>
Date: Fri, 27 Jun 2025 19:16:11 +0200
Subject: [PATCH v3] libpq: Make SSL certificate callback in backend threadsafe
In order to make the errorhandling code in backend libpq be thread-
safe the global variable used by the certificate verification call-
back need to be replaced with passing private data.
Replacing the call to strerror with strerror_r which use an allocated
buffer instead of the static buffer is future work, but is required
for this submodule of libpq to be threadsafe.
Author: Daniel Gustafsson <daniel@yesql.se>
Reviewed-by: Peter Eisentraut <peter@eisentraut.org>
Discussion: https://postgr.es/m/353226C7-97A1-4507-A380-36AA92983AE6@yesql.se
---
src/backend/libpq/be-secure-openssl.c | 31 ++++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index c8b63ef8249..1edbd93c798 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -87,8 +87,14 @@ static bool ssl_is_server_start;
static int ssl_protocol_version_to_openssl(int v);
static const char *ssl_protocol_version_to_string(int v);
-/* for passing data back from verify_cb() */
-static const char *cert_errdetail;
+typedef struct CallbackErr
+{
+ /*
+ * Storage for passing certificate verification error logging from the
+ * callback.
+ */
+ char *cert_errdetail;
+} CallbackErr;
/* ------------------------------------------------------------ */
/* Public interface */
@@ -443,6 +449,7 @@ be_tls_open_server(Port *port)
int waitfor;
unsigned long ecode;
bool give_proto_hint;
+ static CallbackErr err_context;
Assert(!port->ssl);
Assert(!port->peer);
@@ -477,6 +484,10 @@ be_tls_open_server(Port *port)
SSLerrmessage(ERR_get_error()))));
return -1;
}
+
+ err_context.cert_errdetail = NULL;
+ SSL_set_ex_data(port->ssl, 0, &err_context);
+
port->ssl_in_use = true;
aloop:
@@ -576,7 +587,7 @@ aloop:
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("could not accept SSL connection: %s",
SSLerrmessage(ecode)),
- cert_errdetail ? errdetail_internal("%s", cert_errdetail) : 0,
+ err_context.cert_errdetail ? errdetail_internal("%s", err_context.cert_errdetail) : 0,
give_proto_hint ?
errhint("This may indicate that the client does not support any SSL protocol version between %s and %s.",
ssl_min_protocol_version ?
@@ -585,7 +596,8 @@ aloop:
ssl_max_protocol_version ?
ssl_protocol_version_to_string(ssl_max_protocol_version) :
MAX_OPENSSL_TLS_VERSION) : 0));
- cert_errdetail = NULL;
+ if (err_context.cert_errdetail)
+ pfree(err_context.cert_errdetail);
break;
case SSL_ERROR_ZERO_RETURN:
ereport(COMMERROR,
@@ -1209,6 +1221,8 @@ verify_cb(int ok, X509_STORE_CTX *ctx)
const char *errstring;
StringInfoData str;
X509 *cert;
+ SSL *ssl;
+ CallbackErr *cb_err;
if (ok)
{
@@ -1221,6 +1235,13 @@ verify_cb(int ok, X509_STORE_CTX *ctx)
errcode = X509_STORE_CTX_get_error(ctx);
errstring = X509_verify_cert_error_string(errcode);
+ /*
+ * Extract the current SSL and CallbackErr object to use for passing error
+ * detail back from the callback.
+ */
+ ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
+ cb_err = (CallbackErr *) SSL_get_ex_data(ssl, 0);
+
initStringInfo(&str);
appendStringInfo(&str,
_("Client certificate verification failed at depth %d: %s."),
@@ -1271,7 +1292,7 @@ verify_cb(int ok, X509_STORE_CTX *ctx)
}
/* Store our detail message to be logged later. */
- cert_errdetail = str.data;
+ cb_err->cert_errdetail = str.data;
return ok;
}
--
2.39.3 (Apple Git-146)