diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c index 571ae436d5..e19f4f0981 100644 --- a/src/backend/libpq/be-secure-openssl.c +++ b/src/backend/libpq/be-secure-openssl.c @@ -1096,9 +1096,9 @@ initialize_ecdh(SSL_CTX *context, bool isServerStart) * * ERR_get_error() is used by caller to get errcode to pass here. * - * Some caution is needed here since ERR_reason_error_string will - * return NULL if it doesn't recognize the error code. We don't - * want to return NULL ever. + * Some caution is needed here since ERR_reason_error_string will return NULL + * if it doesn't recognize the error code, or (in OpenSSL >= 3) if the code + * represents a system errno value. We don't want to return NULL ever. */ static const char * SSLerrmessage(unsigned long ecode) @@ -1111,6 +1111,19 @@ SSLerrmessage(unsigned long ecode) errreason = ERR_reason_error_string(ecode); if (errreason != NULL) return errreason; + + /* + * In OpenSSL 3.0.0 and later, ERR_reason_error_string randomly refuses to + * map system errno values. We can cover that shortcoming with this bit + * of code. Older OpenSSL versions don't have the ERR_SYSTEM_ERROR macro, + * but that's okay because they don't have the shortcoming either. + */ +#ifdef ERR_SYSTEM_ERROR + if (ERR_SYSTEM_ERROR(ecode)) + return strerror(ERR_GET_REASON(ecode)); +#endif + + /* No choice but to report the numeric ecode */ snprintf(errbuf, sizeof(errbuf), _("SSL error code %lu"), ecode); return errbuf; } diff --git a/src/interfaces/libpq/fe-secure-openssl.c b/src/interfaces/libpq/fe-secure-openssl.c index eddefb02ee..7c4db03607 100644 --- a/src/interfaces/libpq/fe-secure-openssl.c +++ b/src/interfaces/libpq/fe-secure-openssl.c @@ -1355,10 +1355,11 @@ pgtls_close(PGconn *conn) * Obtain reason string for passed SSL errcode * * ERR_get_error() is used by caller to get errcode to pass here. + * The result must be freed after use, using SSLerrfree. * - * Some caution is needed here since ERR_reason_error_string will - * return NULL if it doesn't recognize the error code. We don't - * want to return NULL ever. + * Some caution is needed here since ERR_reason_error_string will return NULL + * if it doesn't recognize the error code, or (in OpenSSL >= 3) if the code + * represents a system errno value. We don't want to return NULL ever. */ static char ssl_nomem[] = "out of memory allocating error description"; @@ -1384,6 +1385,22 @@ SSLerrmessage(unsigned long ecode) strlcpy(errbuf, errreason, SSL_ERR_LEN); return errbuf; } + + /* + * In OpenSSL 3.0.0 and later, ERR_reason_error_string randomly refuses to + * map system errno values. We can cover that shortcoming with this bit + * of code. Older OpenSSL versions don't have the ERR_SYSTEM_ERROR macro, + * but that's okay because they don't have the shortcoming either. + */ +#ifdef ERR_SYSTEM_ERROR + if (ERR_SYSTEM_ERROR(ecode)) + { + strlcpy(errbuf, strerror(ERR_GET_REASON(ecode)), SSL_ERR_LEN); + return errbuf; + } +#endif + + /* No choice but to report the numeric ecode */ snprintf(errbuf, SSL_ERR_LEN, libpq_gettext("SSL error code %lu"), ecode); return errbuf; }